Showing posts with label Deployment. Show all posts
Showing posts with label Deployment. Show all posts

Tuesday, April 9, 2013

Adoption of Agile and Atlassian

Over the past two or three years we have seen companies moving towards adopting Scrum or other variations of agile development. I think the main reasons for this has been to give clients more control over the software that is being developed while having the ability to look at the competitors and apply the changes as seen necessary. This is even truer for products that take more than 6 months from conception to delivery.

Back in late 90s – before the dot com bubble burst – anyone who could write simple HTML could quickly write web pages and in the short term hope to make a lot of money. People did not care about the quality of their products as long as they had it out there. But after that bubble burst, with more and more companies failing, companies started to take software development more seriously. One of the things that came out, although it present decades ago, was adoption of rigid waterfall methodology in software development.

Although, waterfall methodology has its own strengths in documentation, strict scheduling and planning and fixed budget, these last two strengths ultimately becomes its weakness as the complexities of projects grow. This problem increases even more so for lengthier projects. With agile on the other hand, while the problems do not just go away, they’re at the very least addressed. For example, instead of defining all the functions today for a product to be delivered 18 months down the road, we will only look at what can be done within the next sprint. It does not mean that the goal of the project is not understood or unimportant. It just means we’re not cramming our developers, architects, project managers and product owners today with what isn’t possible to do. Instead we want to deliver the client the most important part of the project early so if unforeseen changes are necessary, we can do it early. Changes later in the lifecycle of traditional methodologies mean lots of man hours.

Now how agile fits into Atlassian’s  products is summed up by two words – “Continuous Integration”. Back in 2010 when I worked on project called Project Management Office Dashboard, I was working on integrating JIRA with the PMO Dashboard with the help of Greenhopper’s remote API. We were using Scrum and we needed to be able to streamline JIRA and PMO so that users could access JIRA from within PMO dashboard. While we were working on this, the other tools came in handy such as Crucible for code review. Code review is one of best practices of agile. If we’re writing code and checking in every couple hours with the help of Bamboo (another Atlassian tool) build server, we sure want the code to be reviewed as frequently even if the builds are successful.

So in brief, adoption of agile and using Atlassian tools go hand-in-hand. In the coming years, I am sure there will be some form of agile development and at least a handful of Atlassian set of tools used by most IT companies all over the globe.

Friday, March 1, 2013

Hibernate connection issue with CentOS, MySQL & Tomcat 7

If you are working on CentOS and MySQL, you will want to make sure you verify your connection after the application has been left untouched for some time. Without trying to verify connection you'll end up with a stack trace complaining "Could not open Hibernate Session...". Surprisingly this does not happen on Windows with the same configuration. I am using commons-dbcp.jar and commons-pool.jar. Here is my configuration -

<!--  Define dataSource to use -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${hibernate.jdbc.driver}" />
<property name="url" value="${hibernate.jdbc.url}" />
<property name="username" value="${hibernate.jdbc.user}" />
<property name="password" value="${hibernate.jdbc.password}" />
</bean>

<!--  The sessionFactory will scan the domain objects and their annotated relationships. -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--  Packages to scan probably works but I will use xml definitions -->
<!--
<property name="packagesToScan">
<list>
<value="com.d2.tej.domain" />
<value="com.d2.tej.dao.impl" />
<value="com.d2.tej.service.impl" />
</list>
</property>
-->
<property name="annotatedClasses">
<list>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.AdminUser</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.AdminLogin</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Code</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Patient</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.PatientDetail</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.PodType</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.PodTypeContent</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Practice</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Procedure</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Surgeon</value>
<value>com.OrthoPatientDirect.OPDJAR.core.domain.Subscription</value>
</list>
</property>
<property name="schemaUpdate" value="true" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.isolation">2</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
<!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>-->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<!-- org.hibernate.dialect.MySQLMyISAMDialect, org.hibernate.dialect.MySQLDialect, org.hibernate.dialect.MySQLInnoDBDialect -->
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.max_fetch_depth">2</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!--connection pool-->
<prop key="hibernate.dbcp.maxActive">10</prop>
<prop key="hibernate.dbcp.whenExhaustedAction">1</prop>
<prop key="hibernate.dbcp.maxWait">20000</prop>
<prop key="hibernate.dbcp.maxIdle">10</prop>

<!-- prepared statement cache-->
<prop key="hibernate.dbcp.ps.maxActive">10</prop>
<prop key="hibernate.dbcp.ps.whenExhaustedAction">1</prop>
<prop key="hibernate.dbcp.ps.maxWait">20000</prop>
<prop key="hibernate.dbcp.ps.maxIdle">10</prop>

<!-- optional query to validate pooled connections:-->
<prop key="hibernate.dbcp.validationQuery">select 1</prop>
<prop key="hibernate.dbcp.testOnBorrow">true</prop>
<prop key="hibernate.dbcp.testOnReturn">true</prop>

</props>
</property>
<!--If you want to configure any listeners for any event this is the place to do.  -->
<!--
<property name="eventListeners">
<map>
<entry key="delete">
<bean class="com.tej.core.hibernate.listener.DeleteEventListener" />
</entry>
</map>
</property>
-->
</bean>

Wednesday, June 1, 2011

Creating and consuming a EJB 3 Message Driven Bean Part II

In part I we did all the dirty work - setup JMS connection factory and JMS destination in the application server and then created a stateless session bean that sends message to our XYZ Warehouse application. One thing I forgot to mention is that you'd probably be asking "where is the messaging server?". You might have heard of Active MQ or Webshpere MQ. We're using messaging server included within the AS. So then let's get to creating our MDB.

Create our Message Driven Bean
MessageDrivenBean is just like our stateless bean in the sense it does not retain state. For you and I this means, do not write any code like transaction related code. In the event of any exception you will not be able to recover from this. Little bit confused? Simply understand that it is not your shopper who will have started this transaction for the exception to be returned to the client to handle it. Maybe I should have an article on Transactions. :)

The first thing to do is Annotate the Class with @MessageDriven which tells the AS that this bean is an MDB. You will also have to specify that you want to use the destination "jms/InvoiceQueue". Refer to the source below.  You can then implement MessageListener interface and when you do that you implement void onMessage(Message message) method. Basically, this method encapsulates your business logic or what type of and what message to consume. As with any EJB, you will need an associated EntityManager context to do your CRUDing. But that really is not where I want to focus. What you should get from the code below is that we know we are consuming an ObjectMessage that was sent originally from the producer app. And I'd pointed out that we need an object similar to or at least capable of storing the properties of the Object (Item). We have ItemOrder in this client app to do so.

import com.factory.entities.ItemOrder;
import java.util.ArrayList;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@MessageDriven(mappedName = "jms/InvoiceQueue", activationConfig = {
    @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
    @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class InvoiceMessageBean implements MessageListener {

    @PersistenceContext
    EntityManager em;

    public InvoiceMessageBean() {
    }

    public void onMessage(Message message) {
        try {            
            ObjectMessage objectMessage = (ObjectMessage) message;
            ArrayList list = (ArrayList)objectMessage.getObject();
            ItemOrder itemOrder = new ItemOrder();
            itemOrder.setBarcode(Integer.parseInt(list.get(0).toString()));
            itemOrder.setTotalItemsToOrder(Integer.parseInt(list.get(1).toString()));
            itemOrder.setCompanyID(19284);
            em.persist(itemOrder);
        } catch (JMSException jmse) {
            jmse.printStackTrace();
        }
    }
}


So that's it. You're now ready to create and consume your EJB 3 MDB. You should be able to appreciate all the asynchronous nature of MDB! Enterprise JAVA rules!

Creating and consuming a EJB 3 Message Driven Bean Part I

"Finally, The Rock has come back to...." More like finally, I am going to write an article (albeit two parts article) about programming, if you don't regard SQL as programming. In the first part I am going to write about how to send message to a messaging server including creating a new JMS resource. I used glassfish v2.1 for this. You can use do the same on your preferred application server. In the next part I will write about consuming the message via the MDB. So let's begin. I have created a checklist of functions we need to perform in order deploy our MDB and consume it.

Checklist:


  1. Create a new JMS connection factory to allow creation of JMS objects in the application server. (Messaging server)

  2. Create a new JMS Destination that will be repository for messages sent. (Messaging server)

  3. Use/Create a  session bean to send the message. (Producer Application)

  4. Create our MessageDrivenBean to consume it. (Consumer Application)


Create a new JMS connection factory to allow creation of JMS objects in the application server.
Before we start with creating our MDB and consumer, the first thing I suggest doing is to create a new JMS connection factory in your application server. Think of JMS connection factory as JDBC connection pool. Your JDBC connection pool creates a pool of connection and whenever your application makes a call to get a new connection object, the pool serves it. When you're done the connection object is returned to the pool and if in active and not invalid state, it can serve another connection request. Using pool is just a lot faster and the application server is responsible for managing it. Of course you are responsible for closing the connection so that it can be returned to the pool. We have the option of using javax.jms.TopicConnectionFactory, javax.jms.QueueConnectionFactory or simply javax.jms.ConnectionFactory. Even though we're going to be consuming queues (why? I will explain the difference between a topic an queue) staying true to Abstract Factory Pattern, we will use the inteface ConnectionFactory. Have a look at the image below. I've created a new JMS Connection Factory with JNDI name jms/InvoiceQueueFactory. I've left the Pool Settings to default AS settings.

[caption id="attachment_64" align="alignnone" width="300" caption="JMS Connection Factory"]JMS Connection Factory[/caption]

Create a new JMS Destination that will be repository for messages sent
Now that you've created the Connection Factory we are ready to create a JMS Destination. JMS Destination is where the messages that are sent from the MDB are stored. There are two types of destinations

  • Queue - For point-to-point communication.

  • Topic - For publish-subscribe communication.


What messaging paradigm you want to use is dependent on what your business model is. In the sample MDB, whenever the inventory level of an item in an ABC store reaches below a certain threshold we are going to send an order request  to an XYZ warehouse for the item.

Let's say an instance of ItemOrder class/entity in the Warehouse client app has the following properties

  • int barcode;

  • int totalItemsToOrder;

  • String companyID;


And an instance of Item class/entity in the ABC producer app has the following fields

  • int barcode;

  • String name;

  • double price;

  • int minQuantity;

  • int totalItemsInStock;


Now what happens is when a shopper buys an item with barcode 3884994 from the shop, the totalItemsInStock drops below the minQuantity. What we want to do now is to send a message to the messaging server so that at a later time (may be 5 secs from now or 2 days from now) the Warehouse Application consumes this and sends an packaging and shipping order to its distribution vendor. What is important here is that one and only one message needs to be sent to warehouse. Otherwise, they'd end up sending more than what you need for your store. We would also like to make the message as durable. But this is a configuration in the MDB itself. Later I will discuss this. Anyways, the point is, we need to send a point-to-point message with specific  item barcode and our company ID (their system requirement, apparently) and make sure that message stays there until it is consumed (Hopefully the message does not expire).

You'd use Publish-subscribe when this is not a requirement. Generally, there is a one to many relationship between publisher and subscriber. This won't make sense in our scenario here. So Queue it is!

Creating this is easy. Just use another jndi name like I've done below and specify the type as Queue.

[caption id="attachment_65" align="alignnone" width="300" caption="JMS_Destination_Resource"]JMS_Destination_Resource[/caption]

Use/Create a  session bean to send the message. (Producer Application)
As discussed above, whenever the inventory level drops to below the threshold for that Item, we need to send a message to the Warehouse system via our messaging server to request new orders. What we want to send is our ItemOrder object. I think the valid types are TextMessage, BytesMessage, StreamMessage, ObjectMessage, MapMessage. Please check the API for more info on this. As you may have guessed it, we're going to use ObjectMessage. The caveat here is that you need to have a similar object in the Warehouse system, or at least one with the properties in ItemOrder object. You get the point.

So without further ado, below is a stateless bean that sends a request to the messaging server when the invoice is saved (saveInvoice), if the inventory level drops below the min threshold.

import com.store.entities.Customer;
import com.store.entities.Invoice;
import com.store.entities.Item;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.jms.JMSException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ejb.Remove;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;

@Stateless
public class InvoiceBean implements InvoiceRemote {

    private Invoice invoice = new Invoice();
    @EJB
    private ItemRemote itemService;
    @EJB
    private CustomerRemote customerService;
    @PersistenceContext
    EntityManager em;
    @Resource(name = "jms/InvoiceQueueFactory")
    private ConnectionFactory connectionFactory;
    @Resource(name = "jms/InvoiceQueue")
    private Destination destination;
    private int cartTotal;

    public void addItem(int barcode) {
        Item it = new Item();
        it = (Item) itemService.findItem(barcode);
        if (it.getQuantity() < 1) {
            System.out.println("No item available..........");
        } else {
            it.setQuantity(it.getQuantity() - 1);
            it = (Item) itemService.updateItem(it.getId(), it.getName(), it.getQuantity(), it.getPrice(), it.getBarcode(),
                    it.getMinQuantity(), it.getImage(), it.getItemsToOrder(), it.getShippingCost());
            if(getInvoice().getItems()==null){
                List<Item> items = new ArrayList<Item>();
                items.add(it);
                getInvoice().setItems(items);
                this.setCartTotal(1);
            }else{
                getInvoice().getItems().add(it);
                this.setCartTotal(this.getCartTotal()+1);
            }
            getInvoice().setTotalCost(it.getPrice()+getInvoice().getTotalCost());
        }

    }

    public void removeItem(int barcode) {
        Item it = itemService.findItem(barcode);
        it.setQuantity(it.getQuantity() + 1);
        itemService.updateItem(it.getId(), it.getName(), it.getQuantity(), it.getPrice(), it.getBarcode(),
                it.getMinQuantity(), it.getImage(), it.getItemsToOrder(), it.getShippingCost());
        getInvoice().getItems().remove(it);
        getInvoice().setTotalCost(getInvoice().getTotalCost()- it.getPrice());
        this.setCartTotal(this.getCartTotal()-1);
    }

    @Remove
    public void saveInvoice() {
        em.persist(getInvoice());
        for (Item i : getInvoice().getItems()) {
            Item it = new Item();
            it = itemService.findItem(i.getBarcode());
            if (it.getQuantity() <= it.getMinQuantity()) {

                try {
                    Connection connection = connectionFactory.createConnection();
                    Session session = connection.createSession(true,
                            Session.AUTO_ACKNOWLEDGE);
                    MessageProducer producer = session.createProducer(destination);
                    ObjectMessage message = session.createObjectMessage();
                    ArrayList list = new ArrayList();
                    list.add(it.getBarcode());
                    list.add(it.getItemsToOrder());
                    message.setObject(list);
                    producer.send(message);
                    session.close();
                    connection.close();
                } catch (JMSException ex) {
                    Logger.getLogger(InvoiceBean.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    @Remove
    public void cancelInvoice() {
        this.setCartTotal(0);
        for (Item i : getInvoice().getItems()) {
            Item it = itemService.findItem(i.getBarcode());
            it.setQuantity(it.getQuantity() + 1);
            itemService.updateItem(it.getId(), it.getName(), it.getQuantity(), it.getPrice(),
                    it.getBarcode(), it.getMinQuantity(), it.getImage(), it.getItemsToOrder(), it.getShippingCost());
        }
        setInvoice(new Invoice());
        setCartTotal(0);
    }

    public void addCustomer(int customerID) {

        Customer cust = new Customer();
        cust = (Customer) customerService.findCustomer(customerID);
        System.out.println(cust.getEmail());
        getInvoice().setCustomer(cust);
    }

    /**
     * @return the invoice
     */
    public Invoice getInvoice() {
        return invoice;
    }

    /**
     * @param invoice the invoice to set
     */
    public void setInvoice(Invoice invoice) {
        this.invoice = invoice;
    }

    /**
     * @return the cartTotal
     */
    public int getCartTotal() {
        return cartTotal;
    }

    /**
     * @param cartTotal the cartTotal to set
     */
    public void setCartTotal(int cartTotal) {
        this.cartTotal = cartTotal;
    }
}


As you can see the stateless bean performs its other business methods and when it finally (@Remove to remove its instance and return it to the pool of stateless beans)  savesInvoice, it sends a message to the messaging server, only if the inventory level drops below the minQuantity.

So this takes care of part I. In Part II I will write the Warehouse's MDB.


Tuesday, May 31, 2011

Setting up Maven Enterprise Application Part II

Part II: Setting up individual modules of an EAR






If you've been following along, this is part 2 of two part series in setting up Maven Enterprise Application. Here is part I which shows you how to use maven to setup the overall project structure, configure build path, add module dependencies and libraries. In this second part, I will show you how to structure the individual modules, the JAR and WAR. Since I've assumed that you're using Eclipse/RAD or any other IDE for that matter, I've already discussed how to add WAR to the EAR in part I. From the IDE this is basically adding WAR module dependency to EAR.

Overall View
Before I begin, please see the image below from RAD to see the overall structure. For some of you, this should be enough. You can get this view from Enterprise Explorer in RAD or Project Explorer in Eclipse. Some of you may prefer to use Navigator window. But I am more comfortable with the former two.

[caption id="attachment_53" align="alignnone" width="211" caption="Module Structure"]module_structure[/caption]

JAR Module

The JAR Module will, as I mentioned in Part I, house your model and unit tests for the models. Your model will consist of domains, daos which are your db technology dependent interface and services which are your business interfaces and not underlying db specific. Additionally, you may have custom exception or helper classes.

Your source folder will be under src/main/java. Any resources like perhaps an applicationContext file will be added to src/main/resources. In part I, I mentioned that these locations are added to the classpath. So to read any resource from there you'd write something like classpath*:applicationContext.xml.
Your unit tests (unit tests for JAR module and integration tests for WAR module) will be housed under src/test/java and any resource like applicationContext file will be housed under src/test/resources.

Basically, if you use an ORM tool your domains or entities define relationships and constraints. These domains are package under com.yourComanpyName.applicationName.domain package. You don't write tests for domain objects. Your dao interfaces are packaged under com.yourComanpyName.applicationName.dao and the implementations are packaged under com.yourComanpyName.applicationName.dao.impl. If you're using spring for dependency injection, you'd annotate the implentations as @Repository or define a bean in the application_context.xml file. You would then be able to Autowire your daos to your service and service unit tests. Now daos will have to be unit tested. Therefore you'd create a new package for the tests as com.yourComanpyName.applicationName.dao.impl (same package) under src/test/java. I am not going into details of writing unit tests and daos or any code in this two part series. I will have articles on them later. Now your service methods will be structured similarly to your daos under com.yourComanpyName.applicationName.service and com.yourComanpyName.applicationName.service.impl. You'd want to use DI to initialize them via annotation or xml the same way you'd do for daos because these service methods will be called from WAR module. Your tests for service will go under com.yourComanpyName.applicationName.service.impl under src/test/java. For unit testing you'd want to use a mocking tool like EasyMock or Mockito. You want to mock out the service tests because you do not want to tie up your service to a specific dao implementation. For example, tomorrow you might change from hibernate to using iBatis or JDBC.

So this is basically it as far as your JAR module goes.

WAR Module

The war module will follow the same naming convention as the JAR module. Your sources will be housed under src/main/java and the resources (not web.xml) will be housed under src/main/resources. You can have a folder called WebContent (exists by default in RAD's dynamic application) under which you will have your WEB-INF folder for your web descriptor file (web.xml), static folder for your pages, scripts, css and images. Your tests for source files will be under src/main/test as usual.

Suppose you're using Struts 2, you would then have the action (controllers in Struts 2) classes under com.yourComanpyName.applicationName.web.action package. This is sticking to the naming convention. Your actions will call your injected service interfaces from the JAR module. Your applicationContext file will almost always be the same as what you defined in the JAR module.

Now you'd want to do integration tests in WAR module. The package to create would be the same as for your Action classes (or controllers) but under src/main/test. For integration testing, you'd use a tool to mock out the HttpServletRequest and Session. You can also mock out the db as you did in the service unit tests in the JAR module. That way you are not dependent on dao implementation.

The only thing remaining is to add JAR module as dependency to the WAR module. This I explained in part I. But it is pretty straightforward from the IDE.

You are now all set to start working on your EAR project.

Final Note: I have not covered unit testing or integration testing in any detail for you to be able to go ahead and start writing them. The purpose was only to show you how to setup an EAR using maven. I will have articles related to them later. But the good part is that I won't have to explain the folder structures then. I can always refer to these two articles :)

 

Monday, May 30, 2011

Setting Up Maven Enterprise Application Part I

Part I: Setting up maven and overall structure






This will be the first of 2 part series where I would like to show how to quickly setup a Java Enterprise Application. In this part you will setup the overall project structure, configure your libraries, build path and module dependencies. I use RAD/Eclipse with m2Eclipse plugin which you can find here for development but the configuration is independent of what IDE or text editor you choose to use. So let's get started.

Pre-requisites:

  • Maven 2. I used maven version 2.0.9. For a higher version of maven, please refer to maven documentation.

  • Eclipse/RAD. Although you can do this without an IDE, it will nonetheless be easier to configure in an IDE since this is an Enterprise Application.

  • JDK 1.4 or higher. I prefer JDK 5 or higher.


Overall structure
The enterprise application that I am going to setup will have a JAR module for services and DAOs, a WAR module that will import the JAR module and an EAR module that will include the WAR module. If you wish to add more modules, you can choose similar structure. You could have only WAR and JAR modules in eclipse, but it is preferable to house them within an EAR. Also RAD requires you to have a deployable EAR. Our WAR module will be deployed. To make this a maven project will have also have a parent-pom (which is not a module) sit above all three modules above that will package them together.

Look at the structure below to see how the structure will look like:
Overall Structure

Setting individual modules starting with parent-pom
When you look at the image above, you will see three files: pom.xml, .project, .classpath. All three are important to configure. The IDE will generate your .classpath and .project files but I will nevertheless go through all of them to ensure that you understand what the IDE is generating. Also you can the .settings folder. This folder is specifically related to parent-pom. This folder will contain additional project/IDE related configurations. But I will not go through this because I don't want to make this too long. Also, the configuration for individual modules will be similar to what you will do for parent-pom. If you understand how I am going to configure these three files, you will easily be able to configure the rest.
So let's begin with pom.xml. Pom files are read by maven in order to do the following:

  • Package modules. In this parent pom, you will package all three modules. The package name will be their folder names. In the EAR's pom, you would add the WAR module and in the WAR the JAR module. The JAR module will not have any module dependency.

  • Define versioning, application description, url, name and so on. This is self explanatory. However, you'd want version to be consistent across all modules.

  • Dependencies. You will define all the artifacts and their version that you'd use in your application. In this parent pom, you'd define all artifacts that are common to more than one module. For e.g you'd define log4j here since you'd need logging in both the JAR and WAR module. Same can be said of JUnit and Spring core libraries.

  • Developers and Contributors. Optional. List out the developers/contributors and their roles.

  • Plugin Lists. This lets you define your goals for you build process. For example, you'd use cobertura to see what percentage of your source code is unit tested.

  • Reporting List. Optional. If your need is to generate reports, you'd use this. Again, as I mentioned you'd want to get cobertura report, here's where you define cobertura-maven-plugin.

  • Repositories. A repository is where you'd pull all the artifacts from. Some private repos need authentication, but most don't. While your default settings.xml of maven is a good place to define your repositories, this is also another place to do so.


Please look at the code below for more info:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
This is the 'parent' POM (Project Object Model) which will have the following
nodes inherited by any POM which declared the <parent/> node to point to this
POM. Please note: This is not the 'super POM' which is supplied by Maven itself.
The super POM has its values inherited by all POMs.

* dependencies
* developers and contributors
* plugin lists
* reports lists
* plugin executions with matching ids
* plugin configuration

@author yourName
@version 1.0
-->

<!--
The POM version.
-->
<modelVersion>4.0.0</modelVersion>

<!--
The organization that is creating the artifact. The standard naming convention
is usually the organizations domain name backwards like the package name in Java.
-->
<groupId>com.yourCompanyName.ApplicationName</groupId>

<!--
The artifact name. This will be used when generating the phsyical artifact name.
The result will be artifactId-version.type.
-->
<artifactId>parent-pom</artifactId>

<!--
The type of artifact that will be generated. In this case no real artifact is
generated by this POM, only the sub projects.
-->
<packaging>pom</packaging>

<!--
The version of the artifact to be generated.
-->
<version>0.0.1-SNAPSHOT</version>

<!--
The name of the project to be displayed on the website.
-->
<name>Your Application Name</name>

<!--
The description of the project to be displayed on the website.
-->
<description>
Description of your app
</description>

<!--
The url of the project to be displayed on the website.
-->
<url>http://www.WARModuleURL.com</url>
<!--
This project is an aggregation/multi-module which includes the following
projects. Please note: the value between the module node is the folder
name of the module and not the artifactId value.
-->
<modules>
<module>AppNameJAR</module>
<module>AppNameWAR</module>
<module>AppNameEAR</module>
</modules>

<!--
This segement list the inherited dependencies for each child POM.
-->
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
......
</dependencies>

<!--
The following node defines the developers that are working on the project,
their roles and contact information. This will be used when the site is
generated for the project. (mvn site).

* id - The id of the developer.
* name - The display name that will be used for the display name under 'Project Team' of the website.
* email - The e-mail address of the team member which will be displayed.
* roles - A list of roles the member fulfills.
* organization - The organization of the developer.
* timezone - The timezone of the developer.
-->
<developers>
<developer>
<id>12344</id>
<name>Your Name</name>
<email>yourEamil</email>
<organization>
ABC company INC
</organization>
<organizationUrl>http://www.ABC_Comapnycom</organizationUrl>
<roles>
<role>Technical Leader</role>
</roles>
<timezone>+5:45</timezone>
</developer>
</developers>

<!--
The following node defines the contributors that are working on the project,
their roles and contact information. This will be used when the site is
generated for the project. (mvn site).

* name - The display name that will be used for the display name under 'Project Team' of the website.
* email - The e-mail address of the team member which will be displayed.
* roles - A list of roles the member fulfills.
* organization - The organization of the developer.
* timezone - The timezone of the developer.
-->
<contributors>
<contributor>
<name>SomeName</name>
<email>SomeEmail</email>
<organization>
ABC company INC
</organization>
<organizationUrl>http://www.ABC_Comapnycom</organizationUrl>
<roles>
<role>Engineering Manager</role>
</roles>
<timezone>+5:45</timezone>
</contributor>
...
</contributors>
<!--
Each POM file is a configuration file for the build process. There are many plug-ins
for adding new steps in the build process and controlling which JDK is being used.
Below we customize the version of the JDK as well as some code inspection tools like:

1. Cobertura
-->
<build>
<plugins>
<!--
Configure the maven-compiler-plugin to use JDK 1.5
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
<fork>true</fork>
</configuration>
</plugin>
<!--
Configure Cobertura to ignore monitoring the apache log4j
class.
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<instrumentation>
<ignores>
<ignore>org.apache.log4j.*</ignore>
</ignores>
</instrumentation>
</configuration>

<!--
The following controls under which goals should this
plug-in be executed.
-->
<executions>
<execution>
<goals>
<goal>clean</goal>
<goal>cobertura</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.0.1</version>
<configuration>
<findbugsXmlOutput>true</findbugsXmlOutput>
<includeTests>false</includeTests>
<skip>true</skip>
</configuration>

</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>

</plugins>
</build>

<!--
Maven can look at various repositories to locate dependencies that
need to be downloaded and placed into the local repository. In the
below configuration, we enable codehaus, apache, and opensymphony
repositories.
-->
<repositories>
<repository>
<id>snapshots-maven-codehaus</id>
<name>snapshots-maven-codehaus</name>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
<url>http://snapshots.maven.codehaus.org/maven2</url>
</repository>
<repository>
<id>Maven Snapshots</id>
<url>http://snapshots.maven.codehaus.org/maven2/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-s3</id>
<name>Spring Portfolio Maven MILESTONE Repository</name>
<url>
http://s3.amazonaws.com/maven.springframework.org/milestone
</url>
</repository>
...
</repositories>

<!--
For the reporting area of the website generated.

1. JavaDoc's
2. SureFire
3. Clover
4. Cobertura
5. JDepend
6. FindBugs
7. TagList

-->
<reporting>
<plugins>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<reportOutputDirectory>${site-deploy-location}</reportOutputDirectory>
<destDir>${project.name}</destDir>
<aggregate>true</aggregate>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jxr-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>surefire-report-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-clover-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>cobertura-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<threshold>Normal</threshold>
<effort>Default</effort>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>taglist-maven-plugin</artifactId>
<configuration>
<tags>
<tag>TODO</tag>
<tag>FIXME</tag>
<tag>@todo</tag>
<tag>@deprecated</tag>
</tags>
</configuration>
</plugin>
</plugins>
</reporting>

</project>

Now that this is taken care of let's look into .project and .classpath quickly. The .project basically specifies build Commands. We will use eclipse's javaBuilder and maven2Builder. Look below.

<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>parent-pom</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.maven.ide.eclipse.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.maven.ide.eclipse.maven2Nature</nature>
</natures>
</projectDescription>


.classpath is where you'd define where you want the built packages to reside, your maven repository location, what your source files are and the path to them are. Here's one from the WAR module.

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
<classpathentry kind="src" output="target/classes" path="src/main/resources"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry exported="true" kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
<classpathentry kind="con" path="org.eclipse.jst.server.core.container/com.ibm.ws.ast.st.runtime.runtimeTarget.v61/was.base.v61"/>
<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>


At this stage you have setup the overall project structure, configured your libraries, build path and module dependencies. You are now ready to build individual modules starting with your JAR, then WAR and finally adding them to EAR. You basically add JAR to WAR and only add WAR to EAR. You don't want cycilc dependency. I will show this in part II.

Saturday, May 28, 2011

How to: Send email with attachment from SQL Server 2008 Enterprise Edition

Some time back, I had a problem with exporting huge amount of data as csv to view in excel from a production server. It took several minutes when the server load was normal and far worse when it experienced peak traffic. My client asked me if I could take this feature off of the live server and then automate this process so that he would receive the exported data in the mail instead of requesting data from me. This meant three things, creating a sql job that executed once a week which executed an export script using 'bcp' feature to a file which would then be sent as an attachment to the client. I will explain how to configure SMPT mail server and send email in SQL Server 2008 Enterprise Edition as a two part series.

This is the second of the two part series and here I would like to show how to send email with attachment from SQL Server 2008 Enterprise Edition. If you'd like to follow the first part, here is the link http://dreamfusions.blogspot.com/2010/02/how-to-configure-smtp-mail-server-in.html.

  • Open SQL Server Management Studio (SSMS) and login either using your Windows Authentication or user credentials.

  • Once there, if you don't already see the "Object Explorer" hit F8 to open it.

  • Expand the "Management" folder and right click on "Database Mail".

  • Select "Configure Database Mail".

  • You will need to first create a new profile. To do this, select the first radio option that reads "Set up Database Mail by performing the following tasks."

  • Give a Profile Name and a short description. The Profile Name is important to send emails.

  • Then click on "Add" button to add SMTP server account you configured in part I of this series.

  • Fill out the necessary items. Leave the SMPT port to 25. Enter 127.0.0.1 as your server name. Also if you have Windows Authentication, select that or enter the login you used earlier.

  • Now you are done with profile and mail server account.

  • You can now test by right clicking on Database Mail and clicking on Send Test email.

  • To verify use:SELECT * FROM sysmail_sentitems --to view sent items


SELECT * FROM sysmail_faileditems --to view failed items
SELECT * FROM sysmail_log --to view the reason why your mail was not sent among other things.

  • Now to manually send email (this is our goal), you need to first reconfigure the Database Mail to enable it. To do this run the following scripts.


sp_CONFIGURE 'show advanced', 1
GO
RECONFIGURE
sp_CONFIGURE 'Database Mail XPs' 1
GO
RECONFIGURE


  • You are now ready to send email manually!! The sample script sends email with attachment. You use the msdb database and the profile you created should be entered.


[USE msdb]
GO
EXEC sp_send_dbmail
@profile_name='myMailProfile',
@recipients='tej.rana@hotmail.com',
@subject='Sending message from SQL Server 2008',
@body='You have received mail from SQL Server',
@file_attachments ='c:\Reports\report.csv'


That's all there is to it.

How to: Configure SMTP mail server in Windows Server 2008 and IIS 6.0

Some time back, I had a problem with exporting huge amount of data as csv to view in excel from a production server. It took several minutes when the server load was normal and far worse when it experienced peak traffic. My client asked me if I could take this feature off of the live server and then automate this process so that he would receive the exported data in the mail instead of requesting data from me. This meant three things, creating a sql job that executed once a week which executed an export script using 'bcp' feature to a file which would then be sent as an attachment to the client. I will explain how to configure SMPT mail server and send email as a two part series.

This is the first of the two part series where I would like to show how to configure SMTP mail server in Windows Server 2008.

  • From the Start Menu, navigate to "Administrative Tools" and select "Server Manager".

  • From the "Features Summary" click on "Add Features".

  • Select "SMTP Server" and click on Install. Accept all changes.

  • Now from "Administrative Toos" , select "Internet Information Services (IIS) 6.0 Manager".

  • Right click on "SMTP Virtual Severs" and click on properties.

  • Navigate to "Access" tab and click on "Relay" button.

  • Leave the "Only the list below" radio button clicked and click on "Add" button.

  • Leave the "Single computer" option selecte and enter 127.0.0.1 as your IP address.

  • Now click apply and you are almost done.

  • Right click on "SMTP Virtual Severs" and click on start.


This is it. Now you have SMPT server configured and running!! Follow the next part in this two part series to send mail via SQL Server 2008 Enterprise Edition.