Thursday, April 30, 2015

JBoss module dependency error - Caused by: java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileItemFactory from [Module "org.springframework.spring:1.0.0" from local module loader

I am using file upload feature in Spring frame work. When I added the following line into web-context.xml ( or application-context.xml).

 <bean id="multipartResolver"   
 class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>  

And then I restarted the web server, I got the following error.

 Caused by: java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileItemFactory from [Module "org.springframework.spring:1.0.0" from local module loader @582178a6 (finder: local module finder @7d78077d (roots: C:\act-jboss\jds\runtimes\jboss-eap\modules,C:\act-jboss\jds\runtimes\jboss-eap\modules\system\layers\base))]  
     at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:197) [jboss-modules.jar:1.3.0.Final-redhat-2]  
     at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:443) [jboss-modules.jar:1.3.0.Final-redhat-2]  
     at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:431) [jboss-modules.jar:1.3.0.Final-redhat-2]  
     at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:373) [jboss-modules.jar:1.3.0.Final-redhat-2]  
     at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:118) [jboss-modules.jar:1.3.0.Final-redhat-2]  
     ... 29 more  

The reason of causing the issue is that my current org.springframework.spring doesn't have the dependence module which should include  org.apache.commons.fileupload.FileItemFactory.

In order to make it work, I create a new module called fileupload under apache/commons.
The structure is as below in my system.



The module.xml is as below.

 <?xml version="1.0" encoding="UTF-8"?>  
 <module xmlns="urn:jboss:module:1.1" name="org.apache.commons.fileupload">  
   <resources>  
     <resource-root path="commons-fileupload-1.3.1.jar"/>  
     <!-- Insert resources here -->  
   </resources>  
   <dependencies>       
        <module name="org.apache.commons.io"/>  
        <module name="javax.servlet.api"/>  
   </dependencies>  
 </module>  

Then, go to springframework, to add fileupload module in to module.xml.



  <module name="org.apache.commons.fileupload" />  
 </dependencies>  


Rebuild and restart the server, Now the error is gone.


Tuesday, April 28, 2015

Use bootstrap to display success or error messages

After "Submit" button is clicked, it is very common to display success or error message in the same page instead of refreshing the whole page. (See pictures below.)



After click "Save Classes" button, I have an ajax to post the form data to server side. If it success, a success message will be displayed at the bottom of the form. If ajax call failed, an error message will be displayed. I use BootStrap to display alter messages.

The javascript code for the ajax is as following:

      // Use Ajax to submit form data  
      $.ajax({  
                     url : $form.attr('action'),  
                     type : 'POST',  
                     data : $form.serializeObject(),  
                     success : function(result) {  
                          // ... Process the result ...  
                           $("#result").html('<a href="#" class="close" data-dismiss="alert">&times;</a><strong>Success!</strong> Your message has been sent successfully.');   
                       $("#result").addClass("alert alert-success");  
                     },  
                     error : function(xhr,textStatus,errorThrown) {                           
                           $("#result").html('<a href="#" class="close" data-dismiss="alert">&times;</a><strong>Error!</strong> A problem has been occurred while saving your classes.');   
               $("#result").addClass("alert alert-danger alert-error");  
                     }  
                });  


The following code needs to be added into html code.

 <div id = "result">     </div>  


There are some other bootstrap alert styles. You can find them here.







Wednesday, April 22, 2015

Using jQuery, Bootstrap and Form Validation in a UI development

jQuery:  "jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript. " (From https://jquery.com/)

Bootstrap: "Bootstrap is the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web. Bootstrap makes front-end web development faster and easier. It's made for folks of all skill levels, devices of all shapes, and projects of all sizes. Millions of amazing sites across the web are being built with Bootstrap." (From http://getbootstrap.com/)

FormValidation : "Best jQuery plugin to validate form fields."  (From http://formvalidation.io/ )

In one of my project, I am using jQuery, Bootstrap and a jQuery plug in to do the form validation.
For the detail of each one above, you can just click the links for detail.

I've used jQuery before, this is my first time to use Bootstrap and Form Validation. But this is a very good experience, it makes the UI development job easier and fun.

Below is the form I am building. In the previous blog, I introduced how to use jQuery to build drag and drop sorting table, and how to add a new row or remove a row.

Here, I use Bootstrap form validation to validate the form.


Features for this form:
1, Each row can be drag and drop to the any place. 
2. User can add a new row and remove an existing row.
3. Internal name, display name, Search weight columns are required for each row.
4. If there is a current image, the new image is not required.
5. If there is not a current image, the new image is required.

HTML code as below:

     <form id="classconfigform">  
     <button type="button" class="btn btn-default btn-xs" id="addbutton">Add New Class</button>  
         <table id="classtable" class="table table-striped">  
             <thead>  
                 <tr>  
                     <th class="hidden-xs hidden-sm hidden-md hidden-lg">Order</th>  
                     <th>Class Internal Name</th>  
                     <th>Display Name</th>  
                     <th>Enabled</th>  
                     <th>Search Weight</th>  
                     <th>Current Image</th>  
                     <th>New Image</th>  
                     <th>Delete class</th>  
                 </tr>  
             </thead>  
             <tbody id="sortable">  
                 <c:forEach items="${classes}" var="class">  
                     <tr>  
                         <td class="hidden-xs hidden-sm hidden-md hidden-lg ui-state-default">  
                             <input type="hidden" id="displayOrder" name="displayOrder[]" class="form-control" value='<c:out value="${class.displayOrder}"/>'></input>  
                         </td>  
                         <td><input type="text" id="internalClassName" name="internalClassName[]" class="form-control" placeholder="Class Internal Name" value='<c:out value="${class.internalClassName}"/>'></td>  
                         <td><input type="text" id="displayName" name="displayName[]" class="form-control" placeholder="Display Name" value='<c:out value="${class.displayName}"/>'></td>  
                         <td><input type="checkbox" name="enabled[]" class="form-control" checked ></td>  
                         <td><input type="text" id="searchWeight[]" name="searchWeight[]" class="form-control" value='<c:out value="${class.searchWeight}"/>'></td>  
                         <td><input type="hidden" id="fileid"     name="fileid[]" class="form-control" value='<c:out value="${class.fileStore.fileId}"/>'><img src="${pageContext.request.contextPath}/download/${class.fileStore.fileId}"></td>  
                         <td><input type="file" id="uploadimage"     name="uploadimage[]" class="form-control" value=''>  
                         </td>  
                         <td><button type="button" class="removebutton" title="Remove this class"><span class="glyphicon glyphicon-remove "></span></button> </td>  
                     </tr>  
                 </c:forEach>  
                  <!-- The new row template containing -->  
                 <tr class="hide" id="newClassRowTemplate">  
                         <td class="hidden-xs hidden-sm hidden-md hidden-lg ui-state-default">  
                             <input type="hidden" id="displayOrder" name="displayOrder[]" class="form-control" value='<c:out value="${class.displayOrder}"/>'>  
                         </td>  
                         <td><input type="text" id="internalClassName" name="internalClassName[]" class="form-control" placeholder="Class Internal Name"></td>  
                         <td><input type="text" id="displayName" name="displayName[]" class="form-control" placeholder="Display Name"></td>  
                         <td><input type="checkbox" name="enabled[]" class="form-control" checked ></td>  
                         <td><input type="text" id="searchWeight[]" name="searchWeight[]" class="form-control"></td>  
                         <td><input type="hidden" id="fileid"     name="fileid[]" class="form-control"/> </td>  
                         <td><input type="file" id="uploadimage"     name="uploadimage[]" class="form-control" value=''>  
                      </td>  
                         <td><button type="button" class="removebutton" title="Remove this class"><span class="glyphicon glyphicon-remove "></span></button> </td>  
                 </tr>   
             </tbody>  
         </table>  
     <button type="submit" id="saveClasses" class="btn btn-primary">Save Classes</button>  
     </form>  




Javascript code as below:

 <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->  
 <script src="${pageContext.request.contextPath}/resources/scripts/jquery.js"     type="text/javascript"></script>  
 <script src="${pageContext.request.contextPath}/resources/scripts/jquery-ui.min.js" type="text/javascript"></script>  
 <script    src="${pageContext.request.contextPath}/resources/scripts/bootstrap-3.3.2-dist/js/bootstrap.min.js"    type="text/javascript"></script>  
 <!-- FormValidation CSS file -->  
 <link rel="stylesheet" href="${pageContext.request.contextPath}/resources/scripts/formvalidation-0.6.2/dist/css/formValidation.min.css">  
 <!-- FormValidation plugin and the class supports validating Bootstrap form -->  
 <script src="${pageContext.request.contextPath}/resources/scripts/formvalidation-0.6.2/dist/js/formValidation.min.js"></script>  
 <script src="${pageContext.request.contextPath}/resources/scripts/formvalidation-0.6.2/dist/js/framework/bootstrap.min.js"></script>  
 <script>  
 $(document).ready(function() {  
         $("#sortable").sortable();  
          $('#classconfigform').formValidation({  
             framework: 'bootstrap',  
             err: {  
               container: 'tooltip'  
             },  
             row: {  
               selector: 'td'  
             },  
             icon: {  
               valid: 'glyphicon glyphicon-ok',  
               invalid: 'glyphicon glyphicon-remove',  
               validating: 'glyphicon glyphicon-refresh'  
             },  
             fields: {  
               'internalClassName[]': {  
                 validators: {  
                   notEmpty: {  
                     message: 'Internal class name is required'  
                   }  
                 }  
               },  
               'displayName[]': {  
                 validators: {  
                   notEmpty: {  
                     message: 'Display name is required'  
                   }  
                 }  
               },  
               'searchWeight[]': {  
                 validators: {  
                   notEmpty: {  
                     message: 'Search Weight is required'  
                   }  
                 }  
               },  
         'uploadimage[]': {  
               validators: {  
                                    callback: {  
                     message: 'An image is required',  
                     callback: function (value, validator, $field) {  
                     var $fileid='';  
                     var $classimg =  $field.closest('tr');  
                     $fileid = $classimg.find('#fileid').val();                                          
                     if (($fileid==null||$fileid=='')&&(value==null ||value==''))  
                            return false;  
                     else  
                             return true;      
                     }  
                     }//end of callback                                 
                                }  
                             }               
             }  
           })//end of validation  
 .on("click","#addbutton",function (){  
             var $template = $('#newClassRowTemplate'),  
                         $clone = $template  
                                      .clone()  
                                      .removeClass('hide')  
                                      .removeAttr('id')  
                                      .insertBefore($template)  
                                      .find('input')  
                                      .each(function(){  
                                      $('#classconfigform').formValidation('addField',$(this) );  
                                          });                         
         })  
 .on("click",".removebutton",function () {  
            if (confirm("Do you want to delete the class?")){  
                         var $removeclass =  $(this).closest('tr');  
         $removeclass.remove()  
                .find('input')  
                .each(function(){  
                     $('#classconfigform').formValidation('removeField',$(this) );                                                                       
                    });                  
            }  
     });  
 });  
 </script>  

Challenges in this development:
1. After add/remove  a new row, how to add/remove it from the validation?
There is a simple example (adding dynamic field) from form validation web site. But the form above is more complicated because this one has multiple rows, and each row has multiple fields.

2. Validation on the images.
 (If there is a current image, the new image is not required.
 If there is not a current image, the new image is required.)
This validation need to use a callback function.
The callback function examples can be found here. Since the form above has more rows, so it makes this callback more challenge.

Setup WSO2 ESB server and ActiveMQ server (Part 3) - WSO2 ESB and ActiveMQ connection


I've installed WSO2 and ActiveMQ in the past two blogs.
Setup WSO2 ESB server and ActiveMQ server (Part 1) - Installation
Setup WSO2 ESB server and ActiveMQ server (Part 2)

The WSO2 ESB server - Console URL is https://localhost:9443/carbon/admin/login.jsp
ActiveMQ server - Console URL is http://localhost:8161/admin/queues.jsp

The next we will verify the connection of WSO2 and ActiveMQ.
1. Create a new JMS proxy service. (The same way as in part 2)


2. Replace the source with the following xml doc.

 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="echoJmsProxy"  
     transports="https,http"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <endpoint>  
      <address uri="jms:/EchoQueue?transport.jms.ConnectionFactoryJNDIName=QueueConnectionFactory&amp;  
      java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory&amp;  
      java.naming.provider.url=tcp://localhost:61616"/>  
    </endpoint>  
   </target>  
   <publishWSDL uri="http://localhost:9763/services/echo?wsdl"/>  
   <parameter name="OUT_ONLY">true</parameter>  
   <parameter name="FORCE_SC_ACCEPTED">true</parameter>  
   <description/>  
 </proxy>  

 



3. Click Try this service.
Modify the attribute and click send.


4. Now login to ActiveMQ. We can see there is a message in the queue.


It verified the WSO2 ESB and ActiveMQ connected successfully.




Setup WSO2 ESB server and ActiveMQ server (Part 2)

We will create a simple proxy service to verify WSO2 ESB working fine.

From the part 1, the WSO2 ESB server has been installed in local machine, and we can get into it  through the URL:
The WSO2 ESB server - Console URL is  https://localhost:9443/carbon/admin/login.jsp

There is an echo service built in the wso2 ESB server. We will just add a simple proxy service to make sure it goes through.

    1) Go to WSO2 ESB console. Click on the left side Services - Add - Proxy Service.
On the middle of the window, choose Pass Through Proxy.



   2) Now you get into the page. Enter Proxy service name, and Target URL, then click Create button.



   3) Now you can see the service is in the deployed services list.
       Click source view link.


  4) In the source view window, we will use the follow xml document replace the default one. Then save it.

 <?xml version="1.0" encoding="UTF-8"?>  
 <proxy xmlns="http://ws.apache.org/ns/synapse"  
     name="echoProxy"  
     transports="https,http"  
     statistics="disable"  
     trace="disable"  
     startOnLoad="true">  
   <target>  
    <outSequence>  
      <send/>  
    </outSequence>  
    <endpoint>  
      <address uri="http://localhost:9763/services/echo"/>  
    </endpoint>  
   </target>  
   <publishWSDL uri="http://localhost:9763/services/echo?wsdl"/>  
   <description/>  
 </proxy>  


   5) Now click Try this service 


6) In the try echoProxy service window, we can change the attribute in the request window, then click send, in the response window, we can see the result.



If we get the return number as above, that means the simple proxy service is working in the wso2 esb server.



Thursday, April 16, 2015

Setup WSO2 ESB server and ActiveMQ server (Part 1) - Installation

I have a new project which need to post an xml with a data range to a third party url, then get an xml response back, at last to process the response xml message and save it into database.
I've done this kind of job by using pure java code or Talend ETL open studio.

This time I am trying to using WSO2 ESB server and ActiveMQ server to finish the job.

1. Install ESB and ActiveMQ
 I need to install WSO2 ESB server and ActiveMQ server in my local machine,
These are the version I installed in my local.


2. ESB/ActiveMQ configuration


1) Copy relevant JMS client libraries to WSO2 ESB.
For Apache ActiveMQ, copy
[ActiveMQ_HOME]/lib/
activemq-broker-5.8.0
activemq-client-5.8.0,
geronimo-j2ee-management_1.1_spec-1.0.1.jar and
geronimo-jms_1.1_spec-1.1.1.jar
hawtbuf-1.9

to
[WSO2 ESB HOME]/repository/components/lib

2)  To enable JMS queues, define JNDI in [WSO2 ESB Home]\repository\conf\jndi.properties
connectionfactory.QueueConnectionFactory = amqp://admin:admin@clientID/test?brokerlist='tcp://localhost:61616'

3) Enable JMS Receiver
Edit  Axis2 configuration file ([ESB Home] \repository\conf\axis2\axis2.xml
Uncomment <transportReceiver> section under “<!--Uncomment this and configure as appropriate for JMS transport support, after setting up your JMS environment (e.g. ActiveMQ) -->”

4) Enable JMS Sender
  <!-- uncomment this and configure to use connection pools for sending messages> -->
  <transportSender name="jms" class="org.apache.axis2.transport.jms.JMSSender"/>



3. Start server to verify

Go to [wso2esbhome]\bin directory
run wso2server.bat

Go to [activemq home]\bin 
run activemq.bat

Then I can go to console to verify if the servers are on.

The WSO2 ESB server - Console URL is https://localhost:9443/carbon/admin/login.jsp
ActiveMQ server - Console URL is http://localhost:8161/admin/queues.jsp

The user name and password for both servers are admin/admin.

If everything is correct, we can land on the following web console page.



Wednesday, April 15, 2015

How to get element with its name attribute by using jQuery?

In jQuery, it use # to get id attribute  and . to get  class attribute.

For example, in the jQuery code like this,


 $("#classtable").on("click",".removebutton",function ()  

It will get the attribute from HTML below.

 <table id="classtable" class="table table-striped">  
 ...  
 <button type="button" class="removebutton" title="Remove this class">  
 .....  
 <input type="text" id="displayName" name="displayName" >  

But for the name attribute, we have to use this way:

$('[name="displayName"]').dosomthing();

Friday, April 3, 2015

How to read BLOB column in a database table and save it to a file by using Talend ?

In my development, I saved a file into BLOB column. I would like to check if the data in BLOB column is correct. I use Talend Open Studio  to create a simple job to read BLOB data out of database.

This is the simple job I created in Talend.




In this job, I used a custom component, tLOBDownload. You can download it by click on the name.
If you don't know how to install a custom component, you can reference document in Talend site.
How to install a custom component?


The detail for each component setup is as below.

This is the db2Input setup.

 This is tLOBDownload setup.  Please note the type of file is Object. (Circled in red).
The BLOB will be saved into a file.

Wednesday, April 1, 2015

JPA Relationship between Entities

I have a CompanyClass table and each class can only have one image saved in the filestore table in the database. And the image file saved in Filestore table only match one Companyclass. I would like to use JPA to do data retrieving, saving and removing.


This is a OneToOne mapping relationship in JPA. My entities are like this.

  @Entity   
  @Table(name="COMPANYCLASS", schema="xxx")   
  public class CompanyClass implements Serializable {   
    private static final long serialVersionUID = 1L;   
    @Id   
    @GeneratedValue(strategy=GenerationType.IDENTITY)   
    @Column(name="CLASS_ID",unique = true, nullable = false)   
    private Long classId;   
    @OneToOne (targetEntity=FileStore.class, cascade = CascadeType.ALL)   
    @JoinColumn(name="IMG_ID", referencedColumnName="FILE_ID")   
    private FileStore fileStore; 
    @Column(name="FILE_NAME")   
    private String fileName; 
   ....
    (get and set methods)   
   ....   


 @Entity  
 @Table(name="FILESTORE", schema="xxxx")  
 public class FileStore implements Serializable {  
      private static final long serialVersionUID = 1L;  
      @Id  
      @GeneratedValue(strategy=GenerationType.IDENTITY)  
      @Column(name="FILE_ID" ,unique = true, nullable = false)  
      private Long fileId;  
      @OneToOne(mappedBy="fileStore")  
      private CompanyClass companyClasses;  
 ....  
 (get and set method)       
 ....  

I specified my table primary key to self-incremented in the database side. So I use
 @GeneratedValue(strategy=GenerationType.IDENTITY) 

In this example, my CompanyClass is  the owner. So in the FileStore entity, it is mappedBy ="fileStore". This fileStore is the attribute in the CompanyClass.


  @JoinColumn
A Join Column in JPA is a column in the owner side entity that refers to a key (usually a primary key) in the non-owner or inverse entity.

In the CompanyClass entity, I have
 cascade = CascadeType.ALL
 This means the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.

For example, if I want to insert a new companyclass with an image into database, I can just write code like this.

  EntityManager emgr;  
  CompanyClass cclass = new CompanyClass();  
            FileStore fileStore= new FileStore();  
            fileStore.setFileName = "Image.png";  
            cclass.setFileStore(fileStore);       
  emgr.persist(cclass);  
  emgr.close();