10.26.2012

Apache Tika.

Apache Tika - библиотека предназначенная для определения, извлечения данных и метаданных из различных типов файлов в простой текстовый формат plan text, для последующего анализа содержимого файла и принятия решения что же с ним(файлом) далее делать. Очень часто tika используется как парсер текста файла, и извлеченные данные передаются для дальнейшего анализа поисковым движкам которые в свою очередь индексируют файл и его содержимое. Типы файлов которые поддерживает tika можно посмотреть на сайте http://tika.apache.org/1.2/formats.html. И так  давайте перейдем к работе с парсером tika, что для этого нужно: прежде всего файл, пусть для нашего примера мы будем парсить PDF - файл, далле нам нужен сам  парсер будем использовать спецефический заточенный под PDF-файл PDFParser, но если мы не знаем точный тип файла можно использовать и AutoDetectParser который сам принимает решение, какой парсер вызывать. У парсера есть метод public void parse(java.io.InputStream stream, org.xml.sax.ContentHandler handler,  org.apache.tika.metadata.Metadata metadata, org.apache.tika.parser.ParseContext context); который парсит файл, первый параметр принимает InputStream, источник что мы разбираем в нашем случае это InputStream is2 = new FileInputStream(file); второй параметр ContentHandler будет содержать тело документа/текст, третий параметр будет содержать метаданные - кто создал, когда и т.д., четвертый параметр какой xml-парсер будет использоваться. Давайте рассмотрим пример подробно:
package com.vit;

import org.apache.log4j.Logger;
import org.apache.tika.Tika;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.pdf.PDFParser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class TikaSample {
    private static final String filename = "bs12.pdf";

    public TikaSample() throws IOException, SAXException, TikaException {
        Logger log = Logger.getLogger(this.getClass().getName()); //create Logger
        Metadata metadata = new Metadata(); //create metadata
        Tika tika = new Tika(); //create tika
        InputStream is = getClass().getResourceAsStream(filename);
        File file = new File(filename);
        InputStream is2 = new FileInputStream(file);// create source InputStream
        ParseContext pc = new ParseContext(); //create xml-парсер
        ContentHandler ch = new BodyContentHandler(-1);//сдесь будет содержаться тело документа в виде plan text
        String mimeType = tika.detect(is);//определяем mimeType нашего документа
        metadata.set(Metadata.CONTENT_TYPE, mimeType);//устанавливаем mimeType
        PDFParser parser = new PDFParser(); //create PDFParser
        //AutoDetectParser parser = new AutoDetectParser();//create универсальный парсер который на основе mimeType  принимает решение какой использовать узкоспециализированный парсер
        parser.parse(is2, ch, metadata, pc); //разбор файла на мелкие кусочки
        log.info(ch.toString());//выводим текст документа
        for (String name : metadata.names()) {//выводим метаданные документа
            log.info(name + ": " + metadata.get(name));
        }
        if (is2 != null) is2.close();
        if (is != null) is.close();
    }

    public static void main(String[] args) throws IOException, SAXException, TikaException {
        TikaSample tikaSample = new TikaSample();
    }
}
обратите внимание на -1 при создании  new BodyContentHandler(-1); иначе будет ошибка если большой файл по размеру, это связано с нехваткой памяти куда будет загружается наш документ: Exception in thread "main" org.apache.tika.sax.WriteOutContentHandler$WriteLimitReachedException: Your document contained more than 100000 characters, запускаем нашу программу и получаем такой результат:
...
текст документа 
...
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <meta:creation-date: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <dcterms:modified: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <meta:save-date: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <dcterms:created: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Last-Modified: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <date: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <modified: 2005-04-23T05:28:17Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <xmpTPg:NPages: 25>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Creation-Date: 2005-04-22T18:10:03Z>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <title: PC World Russia CD, May 2005>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <created: Fri Apr 22 22:10:03 MSD 2005>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <producer: Модуль Acrobat Web Capture 6.0>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Content-Type: application/pdf>
2012-10-26 12:50:22,990 INFO [com.vit.TikaSample] - <Last-Save-Date: 2005-04-23T05:28:17Z>
и конечно же приведу файл pom.xml с зависимостями:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vit</groupId>
    <artifactId>spring-jpa-utility</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Spring JPA</name>

    <properties>
        <tika>1.2</tika>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>${tika}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-parsers</artifactId>
            <version>${tika}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox-app</artifactId>
            <version>1.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>1.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-app</artifactId>
            <version>${tika}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Внутренняя кухня hibernate.

Всем новичкам кажется что ORM Hibernate делает разработку проще и код эфективней, но если не знать, некоторых особенностей, то программирование с использованием ORM Hibernate преврашается в кромешный ад. И так что же нужно знать новичку о Hibernate - первое это способ применения, есть стандартный патерн Session per View, который предполагает последовательность правильных действий: Открыть сессию, начать транзакцию, выполнить действия над "pojo-объектом", построить представление на основе "pojo-объекта", закрыть транзакцию, закрыть сессию:
// create a event...
  Session session = sessionFactory.openSession();
  session.beginTransaction();
                Event event = new Event( "Our very first event!", new Date() );
  session.save( event );
  session.getTransaction().commit();
                System.out.println( "Event create" );
  session.close(); 
после закрытия сессии все данные не должны использоваться больше и участвовать в работе приложения. При этом использовать "pojo-объекты" можно только в одном потоке,  который открыл сессию, иначе в работе Hibernate возможны ошибки. Почему нельзя использовать "pojo-объект" после закрытия сессии это связано с особенностью работы Hibernate со сложными "pojo-объектами" которые имеют связи один-к-одному(One-to-one), один-ко-многим(One-to-many) и т.д. при создании связи по умолчанию Hibernate применяет стратегию ленивой загрузки, т.е. за место реальной связи создается прокси-объект без его реального заполнения данными и после завершения сессии, при запросе к прокси-объекту возникает рантаймовое исключение LazyInitializationException. Если вы все-таки хотите работать с "pojo-объектом" после закрытия сессии нужно отключить стратегию ленивой загрузки и переопределить методы equals() и hashCode(). Поясню все на примере, пусть у нас связь person(one) -> address(one):

@Entity
@Table(name="PERSON")
public class Person implements Serializable {
   
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name="personId")
  private int id;

  @OneToOne
  @PrimaryKeyJoinColumn
  private Address address;

  public Address getAddress() {
    return address;
  }
}

@Entity
@Table(name = "ADDRESS")
public class Address {
  @Id
  @Column(name = "personId")
  private int id;
}
....
session.close();
person.getAddress(); --> здесь возникает исключение LazyInitializationException.
я знаю 5 или 6 методов как отключить стратегию ленивой загрузки вот один из них, нужно просто добавить аннотацию для нашего примера @Proxy(lazy=false) и все:
@Entity
@Table(name="PERSON")
@Proxy(lazy=false)
public class Person { 
....
session.close();
person.getAddress();
здесь уже не возникает исключение LazyInitializationException, так как тут уже подгружен реальный объект/коллекция объектов, но нужно быть осторожными с подгружаемыми зависимостями так как это может навредить быстродействию программы и ухудшить её работу, просто нужно найти золотую середину, посредством тестирования кода. Небольшое отступление от темы,  Hibernate нужны интерфейсы для всех сущностей если вы хотите чтобы проксировались подгружаемые объекты через Java Proxy, иначе работа идет через CGLIB, ему не нужны  интерфейсы сущностей и при помощи ASM'а  Hibernate на лету генерирует байт код прокси-объектов, выбор метода проксирования остается за вами,  по умолчанию Hibernate использует CGLIB и интерфейсы ему не нужны. Конечно мы не ищем легких путей и хотим пользоваться "pojo-объектом" и после закрытия сессии изменять их и сохранять сделанные нами изменения с помощью Hibernate, для этого как я упоминал раньше нужно переопределить методы equals() и hashCode(). Вообще я практически всегда эти важные методы наследую и периопределяю, плюс к этому всегда стараюсь наследовать итерфейс Serializable, но пропускаю конструктор "pojo-объекта" по умолчанию, т.к. при создании любого объекта как  new Person() - java автоматически за нас создает и вызывает конструктор по умолчанию. Почему я так настаиваю на переопределении методов equals() и hashCode() я постараюсь объяснить на примере, пусть у нас есть "pojo-объект" без переопределенных методов equals() и hashCode():
public class Entity {
    private int id = 0;
    ....
}
наша программа создает объект Entity и добавляет его в HashSet, далее идут проверки содержит ли HashSet точную копию объекта Entity.
import java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] argv) {
        Entity slimy = new Entity();
        //1
        Set failSet = new HashSet();
        System.out.println(failSet.contains(slimy)); // false
        //2
        failSet.add(slimy);
        System.out.println(failSet.contains(slimy)); // true

        // 3 ID was assigned by an ORM Hibernate 
        slimy.setId(100);
        System.out.println(failSet.contains(slimy)); // true
    }
}
  1. создаем объект и проверяем существует ли объект slimy в HashSet, его там нет // false
  2. заносим объект slimy в HashSet и проверяем существует  ли объект slimy в HashSet - он там присутствует(содержит точную копию) // true
  3. уподобляемся ORM Hibernate и меняем slimy, производим проверку и опять точная  копия содержится в HashSet // true, - ошибка!!!
переопределим методы equals() и hashCode() класса Entity:
public class Entity {
    private int id = 0;
    ....
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Entity other = (Entity) obj;
        if (id != other.id)
            return false;
        return true;
    }
}
заново выполняем программу и на 3-м шаге получаем отрицательный ответ // false объект slimy в HashSet не совпадает с измененным объектом slimy что есть правильно!  Плюс я всегда стараюсь переопределить метод toString() для правильной визуализации  тестовых данных!
Еще новичкам обязательно нужно понять и знать как работает Hibernate cache, без его понимания не стоит и пытаться использовать Hibernate, особенности работы подробно описаны на Хабрахабр'е вот 2 сылки Hibernate cache и Hibernate Cache Практика. Ну вот и все! здесь я дал 30% теории которую вы должны усвоить прежде чем начать работу с ORM Hibernate, 70% придет с практикой!

10.15.2012

Spring MyBatis H2.

В этой статье будет представлен пример интеграции Spring MyBatis + CRUD основных команд MyBatis'a. И так начнем с описания схемы базы данных H2 которая просто встраивается в Spring - schema.sql:
DROP TABLE IF EXISTS PERSON;

CREATE TABLE PERSON (
       ID INT NOT NULL AUTO_INCREMENT
     , FIRST_NAME VARCHAR(20) NOT NULL
     , LAST_NAME VARCHAR(20) NOT NULL
     , BIRTH_DATE DATE
     , UNIQUE UI_PERSON (FIRST_NAME, LAST_NAME)
     , PRIMARY KEY (ID)
);
мы создаем таблицу PERSON где у нас будут храниться данные по человеку его имя, фамилия и дата рождения. Напишем скрип наполняюший эту таблицу произвольными данными - test-data.sql:
insert into person (first_name, last_name, birth_date) values ('Lopanov', 'Vitaly', '1981-08-23');
insert into person (first_name, last_name, birth_date) values ('Kozirev', 'Valera', '1952-01-01');
insert into person (first_name, last_name, birth_date) values ('Aristov', 'Sergey', '1964-10-13');
отобразим нашу табличку доменной моделью реализованной классом Person.java:
package com.vit.domain;

import java.io.Serializable;
import java.util.Date;

public class Person implements Serializable {

    private Long id;
    private String firstName;
    private String lastName;
    private Date birthDate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", birthDate=" + birthDate +
                '}';
    }
}
опишим интерфейс доступа к данным, все операции CRUD:
package com.vit.persistence;

import com.vit.domain.Person;

import java.util.List;

public interface PersonMapper {

    public List findAll();

    public Person findById(Long id);

    public void insert(Person person);

    public void update(Person person);

    public void delete(Long id);

}
с проектируем все SQL-запросы в специальном файле PersonMapper.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.vit.persistence.PersonMapper">

    <resultMap id="personResultMap" type="Person">
        <id property="id" column="ID" />
        <result property="firstName" column="FIRST_NAME" />
        <result property="lastName" column="LAST_NAME" />
        <result property="birthDate" column="BIRTH_DATE" />
    </resultMap>

    <select id="findAll" resultMap="personResultMap">
        SELECT ID, FIRST_NAME, LAST_NAME, BIRTH_DATE
        FROM PERSON
    </select>
    
    <select id="findById" parameterType="long" resultMap="personResultMap">
        SELECT ID,FIRST_NAME,LAST_NAME,BIRTH_DATE
        FROM PERSON
        WHERE ID = #{id}
    </select>
    
    <insert id="insert" parameterType="Person" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO PERSON (FIRST_NAME, LAST_NAME, BIRTH_DATE)
        VALUES (#{firstName}, #{lastName}, #{birthDate})    
    </insert>   
    
    <update id="update" parameterType="Person">
        UPDATE PERSON SET
            FIRST_NAME = #{firstName},
            LAST_NAME = #{lastName},
            BIRTH_DATE = #{birthDate}
        WHERE ID = #{id}   
    </update>       
    
    <delete id="delete" parameterType="long">
        DELETE FROM PERSON WHERE ID = #{id}
    </delete>         
    
</mapper>
Опишем сервисный слой доступа к операциям CRUD c помощью интерфейса PersonService:
package com.vit.service;

import com.vit.domain.Person;

import java.util.List;

public interface PersonService {

    // Find all persons
    public List findAll();

    // Find by ID - person
    public Person findById(Long id);

    // Create a new or save an existing person
    public Person save(Person person);

    // Delete a person
    public void delete(Person person);

}
и реализуем интерфес доступа PersonServiceImpl:
package com.vit.service;

import com.vit.domain.Person;
import com.vit.persistence.PersonMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service("personService")
@Repository
@Transactional
public class PersonServiceImpl implements PersonService {
    @Autowired
    private PersonMapper personMapper;

    public List findAll() {
        List persons = personMapper.findAll();
        return persons;
    }

    public Person findById(Long id) {
        Person person = personMapper.findById(id);
        return person;
    }

    public Person save(Person person) {
        if (person.getId() == null) {
            insert(person);
        } else {
            update(person);
        }
        return person;
    }

    private Person insert(Person person) {
        personMapper.insert(person);
        return person;
    }

    private Person update(Person person) {
        personMapper.update(person);
        return person;
    }

    public void delete(Person person) {
        Long personId = person.getId();
        personMapper.delete(personId);
    }
}
осталось самое интересное интегрировать в Spring - MyBatis все это дело описывается парой строчек в конфигурационном файле ApplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
  http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
    <!-- 1 -->
    <jdbc:embedded-database id="dataSource" type="H2">
        <jdbc:script location="classpath:schema.sql" />
        <jdbc:script location="classpath:test-data.sql" />
    </jdbc:embedded-database>
    <!-- 2 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven />
    <!-- 3 -->
    <context:component-scan base-package="com.vit.service" />

    <!-- 4 Define the SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="com.vit.domain" />
    </bean>

    <!-- 5 Scan for mappers and let them be autowired -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.vit.persistence" />
    </bean>

</beans>
  1. спринг выполняет скрипты, создает и заполняет данными таблицу Person, и настраивается dataSource H2.
  2. создается менеджер транзакций - transactionManager.
  3. задается путь где Spring ищет наши компоненты.
  4. создается SqlSessionFactory mybatis'a.
  5. объект связывающий PersonMapper.xml с интерфейсом доступа к данным PersonMapper.
и осталось показать как работать со спрингом:
package com.vit;

import com.vit.domain.Person;
import com.vit.service.PersonService;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.*;

public class MyBatisSample {

 public static void main(String[] args) {
  GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
  ctx.load("classpath:ApplicationContext.xml");
  ctx.refresh();
  
  PersonService personService = ctx.getBean("personService", PersonService.class);

  List persons;
  
  // Find all persons
  persons = personService.findAll();
  listPersons(persons);

  // Find person by id
  persons = new ArrayList();
  System.out.println("Finding person with id 1");
  Person person = personService.findById(1L);
  persons.add(person);
  listPersons(persons);
  
  // Add new person
  System.out.println("Add new person");
  person = new Person();
  person.setFirstName("Layla");
  person.setLastName("Roberts");
  person.setBirthDate(new Date());
  personService.save(person);
  persons = personService.findAll();
  listPersons(persons);
  
  // Update person
  System.out.println("Update person with id 1");
  person = personService.findById(1L);
  person.setFirstName("Vlad");
  personService.save(person);
  persons = personService.findAll();
  listPersons(persons);

  // Delete person
  System.out.println("Delete person with id 1");
  person = personService.findById(1L);
  personService.delete(person);
  persons = personService.findAll();
  listPersons(persons);
 }
 
 private static void listPersons(List persons) {
  System.out.println("Listing persons without details:");
  for (Person person: persons) {
   System.out.println(person+"\n");
  }
 }
}
и конечно же на последок файл pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.vit</groupId>
    <artifactId>spring-mybatis</artifactId>
    <version>1.0</version>
    <packaging>jar</packaging>
    <name>Spring Utility</name>

    <properties>
                <spring.framework.version>3.1.1.RELEASE</spring.framework.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.framework.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.framework.version}</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>

        <!-- H2 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.160</version>
        </dependency>

        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.1.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

10.12.2012

Vaadin и Spring Security.

В предыдущей статье было показано как интегрировать Spring в Vaadin, продолжаем его улучшать добавив к нему поддержку Spring Security. Я не буду останавливаться на настройке Spring Security просто раскажу как происходит аутентификация - процедура проверки подлинности данных, т. е. проверка соответствия введённого пользователем пароля к учётной записи и паролю в файле application-security.xml. Приведу сразу листинг файла application-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/*" access="hasAnyRole('ROLE_USER','ROLE_ANONYMOUS')"/>
        <form-login login-page="/login" default-target-url="/" authentication-failure-url="/login_error"/>
        <logout invalidate-session="true"/>
    </http>
    <authentication-manager alias="authenticationManager">
        <authentication-provider>
            <user-service>
                <user authorities="ROLE_USER" name="test" password="test"/>
            </user-service>
        </authentication-provider>
    </authentication-manager>
    <global-method-security pre-post-annotations="enabled"/>
</beans:beans>
из него видно что аутентификация происходит на основе формы при помощи странички /login которая дает нам ввести пользователя и пароль, если аутентификация прошла успешно то мы переходим к основной страничке приложения / если нет то выводим страничку с ошибкой /login_error. приведу сразу листинг web.xml с настройками страниц /login - login.jsp, /login_error - login_error.jsp:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
    <display-name>Vaadin Web Application</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
            /WEB-INF/application-security.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vit.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.vit.MyVaadinApplication</param-value>
        </init-param>
    </servlet>
    <servlet>
     <servlet-name>login</servlet-name>
     <jsp-file>/WEB-INF/jsp/login.jsp</jsp-file>
    </servlet>
    <servlet>
     <servlet-name>login_error</servlet-name>
     <jsp-file>/WEB-INF/jsp/login_error.jsp</jsp-file>
    </servlet>
    <servlet-mapping>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
     <servlet-name>login</servlet-name>
     <url-pattern>/login</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
     <servlet-name>login_error</servlet-name>
     <url-pattern>/login_error</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>
            org.springframework.web.filter.DelegatingFilterProxy
        </filter-class>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>
            org.springframework.security.web.session.HttpSessionEventPublisher
        </listener-class>
    </listener>

</web-app>
страничка где вводим пользователя и пароль - листинг login.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
 <div align="center">
 Login here
 <form action= "<%= request.getContextPath() %>/j_spring_security_check" method="post">
 <table>
  <tr>
   <td>
    User
   </td>
   <td>
    <input name="j_username" value="test">
   </td>
  </tr>
  <tr>
   <td>
    Password
   </td>
   <td>
    <input type="password" name="j_password" value="test"/>
   </td>
  </tr>
  <tr>
   <td>
    <input type="submit" value="login">
   <td>
  </tr>
 </table>
 </form> 
 </div>
</body>
</html>
страничка куда попадаем если не правильно ввели данные аутентификации листинг login_error.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
 <H1 align="center">Access Denied</H1>
 <div align="left" >
        <a href="<%= request.getContextPath() %>/login" > Login </a></div>
    <div align="left" ><a href="<%= request.getContextPath() %>" > Home </a></div>
</body>
</html>
При работе с нашим приложение любому пользователю, Spring'ом присваивается роль ROLE_ANONYMOUS, если пользователь успешно прошёл аутентификацию, то ему присваивается роль ROLE_USER.
package com.vit;

public interface Roles {
    String ROLE_USER = "ROLE_USER";
    String ROLE_ANONYMOUS = "ROLE_ANONYMOUS";
}
С помощью метода hasAnyRole(ROLE_USER) мы можем узнать залогинелся ли пользователь и соответственно раздавть ему полагаемые ресурсы, данные. Сылки "Login" и "Logout" я вынеc в одельную панель HeadPanel:
package com.vit;

import com.vaadin.terminal.ExternalResource;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.BaseTheme;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.Collection;
import static com.vit.Roles.ROLE_USER;
import static com.vit.Roles.ROLE_ANONYMOUS;

public class HeadPanel extends Panel {
    public HorizontalLayout hLayout;
    public HorizontalLayout cssLayout;

    public HeadPanel() {
        setImmediate(true);
        cssLayout = new HorizontalLayout();
        cssLayout.setSpacing(true);

        hLayout = new HorizontalLayout();
        hLayout.setWidth("100%");

        if (hasAnyRole(ROLE_ANONYMOUS)) {
            Button b = new Button("LOGIN");
            b.setStyleName(BaseTheme.BUTTON_LINK);
            b.setWidth("60px");
            b.addListener(new Button.ClickListener() {
                public void buttonClick(Button.ClickEvent clickEvent) {
                    final String path = getApplication().getURL().getPath();
                    getApplication().getMainWindow().open(
                            new ExternalResource(path + "login"));
                }
            }); // react to clicks
            cssLayout.addComponent(b);
            cssLayout.setComponentAlignment(b, Alignment.MIDDLE_LEFT);
        } else {
            Label userName = new Label(currentUserName());
            userName.setWidth("130px");
            cssLayout.addComponent(userName);
            cssLayout.setComponentAlignment(userName, Alignment.MIDDLE_LEFT);
        }
        if (hasAnyRole(ROLE_USER)) {
            Button logout = new Button("Loguot");
            logout.setStyleName(BaseTheme.BUTTON_LINK);
            logout.setWidth("60px");
            logout.addListener(new Button.ClickListener() {
                private static final long serialVersionUID = 1L;

                public void buttonClick(Button.ClickEvent clickEvent) {
                    LoguotWindow loguotWindow = new LoguotWindow("", "Are you sure?");
                    getApplication().getMainWindow().addWindow(loguotWindow);
                }
            });
            cssLayout.addComponent(logout);
            cssLayout.setComponentAlignment(logout, Alignment.MIDDLE_LEFT);
        }
        hLayout.addComponent(cssLayout);
        hLayout.setComponentAlignment(cssLayout, Alignment.MIDDLE_RIGHT);
        addComponent(hLayout);
    }

    public boolean hasAnyRole(String... roles) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Collection authorities = (Collection) authentication.getAuthorities();
        for (GrantedAuthority authority : authorities) {
            for (String role : roles) {
                if (role.equals(authority.getAuthority())) {
                    return true;
                }
            }
        }
        return false;
    }

    public String currentUserName() {
        return SecurityContextHolder.getContext().getAuthentication().getName();
    }
}
При завершении работы пользователя в Vaadin мы должны очистить асоциированные данные с ним посредством вызова метода getApplication().close(); и предупредить Spring что мы сделали "Logout".
package com.vit;

import com.vaadin.ui.*;

public class LoguotWindow extends Window {

    public VerticalLayout vLayout;
    public Label qLabel;
    public HorizontalLayout hLayout;
    public Button close;
    public Button closeWindow;

    public LoguotWindow(String caption, String qCaption) {
        super(caption);
        center();
        setImmediate(true);
        setClosable(true);
        setModal(true);
        setWidth("200px");
        setHeight("200px");
        setScrollable(false);
        vLayout = new VerticalLayout();
        vLayout.setSpacing(true);
        vLayout.setSizeFull();
        qLabel = new Label(qCaption);
        vLayout.addComponent(qLabel);
        hLayout = new HorizontalLayout();
        hLayout.setSpacing(true);
        close = new Button("YES", new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            public void buttonClick(Button.ClickEvent event) {
                // close the window by removing it from the parent window
                getApplication().close();
                getParent().removeWindow(getWindow());
            }
        });
        hLayout.addComponent(close);
        closeWindow = new Button("NO", new Button.ClickListener() {
            private static final long serialVersionUID = 1L;

            public void buttonClick(Button.ClickEvent event) {
                // close the window by removing it from the parent window
                getParent().removeWindow(getWindow());
            }
        });
        hLayout.addComponent(closeWindow);
        vLayout.addComponent(hLayout);
        hLayout.setSizeFull();
        vLayout.setComponentAlignment(hLayout, Alignment.MIDDLE_CENTER);
        addComponent(vLayout);
    }
}
При вызове метода getApplication().close(); Vaadin делает redirect по методу setLogoutURL(getURL().getPath() + "j_spring_security_logout"); который дает понят Spring'у что пользователь вышел и спринг "удаляет" все данные связанные с пользователем, в свою очередь он делает redirect в корень / web приложения вот и все:
public class MyVaadinApplication extends Application {
    private Window window;
    public Button button;
    private HeadPanel headPanel;
    @Autowired(required = true)
    private TestBean testBean;

    @Override
    public void init() {
        setTheme("runo");
        window = new Window("Hello Vaadin!");
        setMainWindow(window);
        setLogoutURL(getURL().getPath() + "j_spring_security_logout");
        window.setImmediate(true);

        headPanel = new HeadPanel();
        headPanel.setSizeFull();
        window.addComponent(headPanel);
        Button button = new Button("Click Me");
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                if (headPanel.hasAnyRole(ROLE_USER)) {
                    Label label = new Label("you are ROLE_USER");
                    window.addComponent(label);
                } else {
                    Label label = new Label("you are not Login");
                    window.addComponent(label);
                }
            }
        });
        window.addComponent(button);
    }
}
Привожу pom.xml c зависимостями
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.vit</groupId>
    <artifactId>VaadinTest11</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>Vaadin Web Application</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <vaadin.version>6.6.6</vaadin.version>
        <gwt.version>2.3.0</gwt.version>
        <gwt.plugin.version>2.2.0</gwt.plugin.version>
        <spring.version>3.1.1.RELEASE</spring.version>
        <spring-security.version>3.1.0.RELEASE</spring-security.version>
    </properties>

    <build>
        <finalName>test</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

            <!-- A simple Jetty test server at http://localhost:8080/VaadinTest11 can be launched with the Maven goal jetty:run
        and stopped with jetty:stop -->
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.24</version>
                <configuration>
                    <stopPort>9966</stopPort>
                    <stopKey>VaadinTest11</stopKey>
                    <!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
                    <scanIntervalSeconds>0</scanIntervalSeconds>
                    <!-- make sure Jetty also finds the widgetset -->
                    <webAppConfig>
                        <contextPath>/VaadinTest11</contextPath>
                        <baseResource implementation="org.mortbay.resource.ResourceCollection">
                            <!-- Workaround for Maven/Jetty issue http://jira.codehaus.org/browse/JETTY-680 -->
                            <!-- <resources>src/main/webapp,${project.build.directory}/${project.build.finalName}</resources> -->
                            <resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}
                            </resourcesAsCSV>
                        </baseResource>
                    </webAppConfig>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>vaadin-snapshots</id>
            <url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>vaadin-addons</id>
            <url>http://maven.vaadin.com/vaadin-addons</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin</artifactId>
            <version>${vaadin.version}</version>
        </dependency>

        <!-- Spring Dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-support</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xbean</groupId>
            <artifactId>xbean-spring</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.6.6</version>
        </dependency>

        <!-- http://repo1.maven.org/maven -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1</version>
        </dependency>
        <!--spring-security-->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring-security.version}</version>
            <type>jar</type>
        </dependency>
    </dependencies>

</project>

10.11.2012

Vaadin и Spring @Autowired.

Здесь я хочу познокомить вас с еще одной моей наработкой, а именно как я подключаю  Spring фраемворк к Vaadin. И так начнем с создания простейшего bean'а который возврашает нам Spring, а у него метод public String getTestString() возвращает нам простую строчку
"  -= TestString SPRING =- ", сначало опишим его interface:
package com.vit.bean;

public interface TestBean {
    public String getTestString();
} 
потом его реализацию:
package com.vit.bean;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component("test")
@Scope(value = "prototype")
public class TestBeanImpl implements TestBean{

    public String getTestString() {
        return "  -= TestString SPRING =- ";
    }
} 
Далее нам нужно описать класс сервлет который будет инжектить наши бины в компоненты Vaadin'е.
package com.vit;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.ApplicationServlet;

public class AutowiringApplicationServlet extends ApplicationServlet {
 private static final long serialVersionUID = 1L;
 private WebApplicationContext webApplicationContext;

 @Override
 public void init(ServletConfig config) throws ServletException {
  super.init(config);
  try {
   this.webApplicationContext = WebApplicationContextUtils.
                    getRequiredWebApplicationContext(config.getServletContext());
  } catch (IllegalStateException e) {
   throw new ServletException("could not locate containing WebApplicationContext");
  }
 }

 protected final WebApplicationContext getWebApplicationContext() throws ServletException {
  if (this.webApplicationContext == null)
   throw new ServletException("can't retrieve WebApplicationContext before init() is invoked");
  return this.webApplicationContext;
 }

 protected final AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws ServletException {
  try {
   return getWebApplicationContext().getAutowireCapableBeanFactory();
  } catch (IllegalStateException e) {
   throw new ServletException("containing context " + getWebApplicationContext() + " is not autowire-capable", e);
  }
 }

 @Override
 protected Application getNewApplication(HttpServletRequest request) throws ServletException {
  Class cl = null;
  try {
   cl = getApplicationClass();
  } catch (ClassNotFoundException e1) {
   e1.printStackTrace();
  }
  AutowireCapableBeanFactory beanFactory = getAutowireCapableBeanFactory();
  try {
   return beanFactory.createBean(cl);
  } catch (BeansException e) {
   throw new ServletException("failed to create new instance of " + cl, e);
  }
 }
} 
после этого нужно настроить все в web.xml что бы обработка шла через наш сервлет:
<servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vit.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.vit.MyVaadinApplication</param-value>
        </init-param>
    </servlet>
описывать настройку Spring'a для веб не буду просто приведу полный листинг web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
    <display-name>Vaadin Web Application</display-name>
    <context-param>
        <description>Vaadin production mode</description>
        <param-name>productionMode</param-name>
        <param-value>false</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/applicationContext.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <servlet-class>com.vit.AutowiringApplicationServlet</servlet-class>
        <init-param>
            <param-name>application</param-name>
            <param-value>com.vit.MyVaadinApplication</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Vaadin Application Servlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>characterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

</web-app>
в файле конфигурации Spring делаю минимальные настройки для работы аннотаций:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <context:annotation-config />
    <!-- Turn on AspectJ @Configurable support -->
    <!--<context:spring-configured/>-->
    <context:component-scan base-package="com.vit.bean"/>
    <!-- Turn on @Autowired, @PostConstruct etc support -->
 <beans:bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
 <beans:bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />

</beans>
Собственно осталось только привести тело основной программы:
package com.vit;

import com.vaadin.Application;
import com.vaadin.data.Property;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Runo;
import com.vit.bean.TestBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;

@SuppressWarnings("serial")
@Configurable(preConstruction = true, dependencyCheck = true)
public class MyVaadinApplication extends Application {
    private Window window;
    public Button button;
    @Autowired(required = true)
    private TestBean testBean;

    @Override
    public void init() {
        setTheme("runo");
        window = new Window("Hello Vaadin!");
        setMainWindow(window);
        window.setImmediate(true);
        button = new Button("Button.text");
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                window.addComponent(new Label("Label.text"+testBean.getTestString()));
            }
        });
        button.addStyleName(Runo.BUTTON_SMALL);
        window.addComponent(button);
    }
} 
в строчке мы уже имем любездно созданный Spring'om бин @Autowired(required = true) private TestBean testBean; в строчке new Label("Label.text"+testBean.getTestString()) вызываем getTestString() который возвращает нам строку " -= TestString SPRING =- " Спринг дает нам новые возможности по использованию Vaadin'a и через него мы можем подключить какие угодно вкусности типа Hibernate, Mybatis, JDBC and etc ... Осталось в этой статье только привести зависимости maven'a:
 <?xml version="1.0" encoding="UTF-8"?>
<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">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.vit</groupId>
  <artifactId>VaadinTest11</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Vaadin Web Application</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <vaadin.version>6.6.6</vaadin.version>
    <gwt.version>2.3.0</gwt.version>
    <gwt.plugin.version>2.2.0</gwt.plugin.version>
    <spring.version>3.1.1.RELEASE</spring.version>
  </properties>

  <build>
    <finalName>test</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

      <!-- A simple Jetty test server at http://localhost:8080/VaadinTest11 can be launched with the Maven goal jetty:run 
        and stopped with jetty:stop -->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.1.24</version>
        <configuration>
          <stopPort>9966</stopPort>
          <stopKey>VaadinTest11</stopKey>
          <!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
          <scanIntervalSeconds>0</scanIntervalSeconds>
          <!-- make sure Jetty also finds the widgetset -->
          <webAppConfig>
            <contextPath>/VaadinTest11</contextPath>
            <baseResource implementation="org.mortbay.resource.ResourceCollection">
              <!-- Workaround for Maven/Jetty issue http://jira.codehaus.org/browse/JETTY-680 -->
              <!-- <resources>src/main/webapp,${project.build.directory}/${project.build.finalName}</resources> -->
              <resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}</resourcesAsCSV>
            </baseResource>
          </webAppConfig>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>vaadin-snapshots</id>
      <url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>vaadin-addons</id>
      <url>http://maven.vaadin.com/vaadin-addons</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>com.vaadin</groupId>
      <artifactId>vaadin</artifactId>
      <version>${vaadin.version}</version>
    </dependency>
    <!-- Spring Dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <!-- Exclude Commons Logging in favor of SLF4j -->
                <exclusion>
                    <groupId>commons-logging</groupId>
                    <artifactId>commons-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <type>jar</type>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-support</artifactId>
            <version>2.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
      <!-- logging -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-jdk14</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xbean</groupId>
            <artifactId>xbean-spring</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.6</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>1.6.6</version>
        </dependency>

      <!-- http://repo1.maven.org/maven -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.1</version>
        </dependency>
  </dependencies>

</project>

Vaadin Internationlization localization.

Впервые познакомившись с Vaadin я был в восторге от него, но со временем интерес к нему прошел, из-за ряда вещей но кое-какие наработки остались.Вот одна из наработок - это как наиболле просто локализовать программу, точнее где правильно хранить локаль пользователя. Правильно хранить локаль и другие данные нужно в глобальной сессии пользователя, для этого нужно создать ThreadLocal сингильтон который будет содержать объекты ResourceBundle bundle, Locale locale, Application app и сингильтон при этом должен наследовать interface ApplicationContext.TransactionListener - у этого интерфейса есть 2 метода:
public void transactionStart(Application application,
                                 Object transactionData) {     
        if (this.app == application)
            instance.set(this);
    }
который связывает данные пользователя с текушим потоком во ThreadLocal и
public void transactionEnd(Application application,
                               Object transactionData) {
        // Clear the reference to avoid potential problems
        if (this.app == application)
            instance.set(null);
    }
который разрывает эту связь. Коротко что мы здесь сделали - ThreadLocal позволяет нам хранить разные данные для каждого пользователя, т.е. для каждого потока(сессии пользователя) будут разные значения объектов ResourceBundle bundle, Locale locale.
package com.vit;

import com.vaadin.Application;
import com.vaadin.service.ApplicationContext;

import java.io.Serializable;
import java.util.Locale;
import java.util.ResourceBundle;

/** Holds data for one user session. */
public class AppData implements ApplicationContext.TransactionListener, Serializable {
    private ResourceBundle bundle;
    private Locale locale;   // Current locale
    private Application app; // For distinguishing between apps

    private static ThreadLocal instance =
        new ThreadLocal();

    public AppData(Application app) {
        this.app = app;
        // It's usable from now on in the current request
        instance.set(this);
    }

    @Override
    public void transactionStart(Application application,
                                 Object transactionData) {
        // Set this data instance of this application
        // as the one active in the current thread.
        if (this.app == application)
            instance.set(this);
    }

    @Override
    public void transactionEnd(Application application,
                               Object transactionData) {
        // Clear the reference to avoid potential problems
        if (this.app == application)
            instance.set(null);
    }

    public static void initLocale(Locale locale,
                                  String bundleName) {
        instance.get().locale = locale;
        instance.get().bundle =
            ResourceBundle.getBundle(bundleName, locale);
    }

    public static Locale getLocale() {
        return instance.get().locale;
    }

    public static String getMessage(String msgId) {
        return instance.get().bundle.getString(msgId);
    }
}
Дальше создаем ComboBox который позволяет нам менять текушую локаль и соответственно настроить под неё ResourceBundle.
package com.vit;

import com.vaadin.ui.ComboBox;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

public class ComboBoxLocale extends ComboBox{
    private final List locales = Arrays.asList(
            new Locale("ru", "RU"), Locale.US, Locale.ENGLISH, AppData.getLocale());

    public ComboBoxLocale(String caption) {
        super(caption);
        for (Locale l:locales) {
            addItem(l);
            setItemCaption(l,l.getDisplayName());
        }
        setNullSelectionAllowed(false);
        setImmediate(true);
        setVisible(true);
    }

    @Override
    public void attach() {
        super.attach();
        setValue(AppData.getLocale());
    }
}
Далее создаем файл ресурсов для английского языка MyVaadinApplication_en.properties:
Button.text=Click me English
Label.text=Thank you for clicking Еnglish
и для русского MyVaadinApplication_ru_RU.properties:
Button.text=Click me Russian
Label.text=Thank you for clicking Russian
И наконец все встраиваем в наше веб приложение.
package com.vit;

import com.vaadin.Application;
import com.vaadin.data.Property;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Runo;

import java.util.Locale;

public class MyVaadinApplication extends Application {
    private Window window;
    public ComboBoxLocale comboBoxLocale;
    public Button button;

    @Override
    public void init() {
        setTheme("runo");
        window = new Window("Hello Vaadin!");
        setMainWindow(window);
        window.setImmediate(true);
        // Create the application data instance
        AppData sessionData = new AppData(this);
        // Register it as a listener in the application context
        getContext().addTransactionListener(sessionData);
        // Initialize the session-global data
        AppData.initLocale(getLocale(),
                MyVaadinApplication.class.getSimpleName());

        comboBoxLocale = new ComboBoxLocale("Change Locale:");
        comboBoxLocale.setWidth("150px");
        comboBoxLocale.setValue(getLocale());
        Property.ValueChangeListener listener = new Property.ValueChangeListener() {
            public void valueChange(Property.ValueChangeEvent event) {
                AppData.initLocale((Locale) comboBoxLocale.getValue(),
                        MyVaadinApplication.class.getSimpleName());
                setLocale((Locale) comboBoxLocale.getValue());
                window.showNotification(
                        ((Locale) comboBoxLocale.getValue()).getDisplayName() + " : " +
                                AppData.getLocale().getLanguage() );
                button.setLocale((Locale) comboBoxLocale.getValue());
                button.setCaption(AppData.getMessage("Button.text"));
            }
        };
        comboBoxLocale.addListener(listener);
        window.addComponent(comboBoxLocale);

        button = new Button(AppData.getMessage("Button.text"));
        button.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                window.addComponent(new Label(AppData.getMessage("Label.text")));
            }
        });
        button.addStyleName(Runo.BUTTON_SMALL);
        window.addComponent(button);
    }
}
Опишу пару строк важных строк создаем наш сингильтон - AppData sessionData = new AppData(this); регистрируем наш обработчик - getContext().addTransactionListener(sessionData); устанвливаем текушую локаль и связываем с ним ResourceBundle - AppData.initLocale(getLocale(),MyVaadinApplication.class.getSimpleName()); создаем кнопку и выдергиваем строчку Button.text из ResourceBundle - button = new Button(AppData.getMessage("Button.text")); Вот и все на последок привожу файл pom.xml с зависимостями:
<?xml version="1.0" encoding="UTF-8"?>
<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">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.vit</groupId>
  <artifactId>VaadinTest11</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Vaadin Web Application</name>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <vaadin.version>6.6.6</vaadin.version>
    <gwt.version>2.3.0</gwt.version>
    <gwt.plugin.version>2.2.0</gwt.plugin.version>
  </properties>

  <build>
    <finalName>test</finalName>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.5</source>
          <target>1.5</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>

      <!-- A simple Jetty test server at http://localhost:8080/VaadinTest11 can be launched with the Maven goal jetty:run 
        and stopped with jetty:stop -->
      <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>maven-jetty-plugin</artifactId>
        <version>6.1.24</version>
        <configuration>
          <stopPort>9966</stopPort>
          <stopKey>VaadinTest11</stopKey>
          <!-- Redeploy every x seconds if changes are detected, 0 for no automatic redeployment -->
          <scanIntervalSeconds>0</scanIntervalSeconds>
          <!-- make sure Jetty also finds the widgetset -->
          <webAppConfig>
            <contextPath>/VaadinTest11</contextPath>
            <baseResource implementation="org.mortbay.resource.ResourceCollection">
              <!-- Workaround for Maven/Jetty issue http://jira.codehaus.org/browse/JETTY-680 -->
              <!-- <resources>src/main/webapp,${project.build.directory}/${project.build.finalName}</resources> -->
              <resourcesAsCSV>src/main/webapp,${project.build.directory}/${project.build.finalName}</resourcesAsCSV>
            </baseResource>
          </webAppConfig>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>vaadin-snapshots</id>
      <url>http://oss.sonatype.org/content/repositories/vaadin-snapshots/</url>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
    <repository>
      <id>vaadin-addons</id>
      <url>http://maven.vaadin.com/vaadin-addons</url>
    </repository>
  </repositories>

  <dependencies>
    <dependency>
      <groupId>com.vaadin</groupId>
      <artifactId>vaadin</artifactId>
      <version>${vaadin.version}</version>
    </dependency>
  </dependencies>

</project>

10.10.2012

Apache Ivy

Познакомитесь Apache Ivy очень интересный проект для программистов Java. В чем его интересность - он позволяет разработчику управлять зависимостями java библиотек при компиляции и развертывании java  приложений т.е. автоматизировать сборку приложения в области закачки нужных вам java библиотек. Ivy тесно интегрирован с проектом Apache Ant - java-утилитой для автоматизации процесса сборки java приложений. В принципе как я понял из документации Ivy можно использовать и отдельно без ant, но куда интереснее в связке с Ant. При работе над проектом все недостаюшие вам ява библиотеки будут скачаны  из репозитария. По умолчанию используется центральный Maven репозитарий, но если необходимо то можно использовать свой допустим Apache Archiva - http://archiva.apache.org, все гибко настраивается в Ivy. Давайте расмотрим все по порядку: установку,настройку, и работу примера. Для установки  Apache Ivy вам нужно скачать с официального сайта последнию версию, распаковать архив, с копировать ivy*.jar (в моем случае ivy-2.2.0.jar) в lib директорию Apache Ant, т.е. у вас на компьютере ivy*.jar должна находиться в ANT_HOME/lib. Давайте перейдем к простому примеру который поставляется вместе с Ivy: src/example/hello-ivy, пример состоит из 3-х файлов - Hello.java простой файл при компиляции которому нужны 2 java библиотеки: commons-lang-2.0.jar и commons-cli-1.0.jar т.е. можно сказать что наше приложение зависит от 2 артифактов, которые мы каким-то образом должны получить. Все зависимости мы должны описать в файле конфигурации ivy.xml:
<ivy-module version="2.0"> - все настройки начинаются этим тегом и соотвественно заканчиваются, версия файла настройки 2.0
<info organisation="org.apache" module="hello-ivy"/> информационный тег существенной роли не играет, нужен для формирования имени файлов отчета в кеше - org.apache-hello-ivy-default.xml.
<dependencies> - начало описания наших зависимотей
        <dependency org="commons-lang" name="commons-lang" rev="2.0"/> - 1-й артифакт который нам нужен 
        <dependency org="commons-cli" name="commons-cli" rev="1.0"/>   - и 2-й артифакт который нам нужен 
</dependencies>
Т.к. по умолчанию используется публичный репозиторий ibiblio http://repo2.maven.org/maven2 , будем разрешать зависимости используя его - найти нужную зависимость можно вручную:) Для этого, необходимо нам Maven POM Dependency(pom.xml если вы мигрируете с Maven'a) или maven-metadata.xml. Допустим мне нужна poi библиотека(артифакт) я захожу на репозитарий http://repo2.maven.org/maven2/poi/poi-2.5-final/ открываю maven-metadata.xml и переписываю зависимость

  <dependency>
    <groupId>poi</groupId>
    <artifactId>poi-2.5-final</artifactId>
    <version>20040302</version>
  </dependency>
как <dependency org="groupId" name="artifactId" rev="version"/>:
 <dependency org="poi" name="poi-2.5-final" rev="20040302"/>
Вот разобрались с нашими зависимостями, перейдем к файлу конфигурации ant - build.xml:
<project name="hello-ivy" default="run" xmlns:ivy="antlib:org.apache.ivy.ant"> 
    1-е нам нужно подключить Ivy - делается это следующим образом подключаем новое 
    пространство имен xmlns:ivy="antlib:org.apache.ivy.ant" - и все что начинается с <ivy: ... />
    будет относится к вызову команд ivy а не ant'a например: <ivy:retrieve/> - команда ivy.
    <!-- переменные нашего проекта -->
    <property name="lib.dir" value="lib" />
    <property name="build.dir" value="build" />
    <property name="src.dir" value="src" />
    
    <!-- пути где лежат наши библиотеки(артифакты) они будут 
     использоваться при компиляции и выполнении программы  -->
    <path id="lib.path.id">
        <fileset dir="${lib.dir}" />
 </path>
    <path id="run.path.id">
        <path refid="lib.path.id" />
        <path location="${build.dir}" />
    </path>
    
    <!-- ================================= 
          target: resolve              
         ================================= -->
    <target name="resolve" description="--> retreive dependencies with ivy">
        <ivy:retrieve/> - с начала происходит загрузка наших зависимостей в локальный репозитарий,
         по умолчанию в ваш домашний каталог (user home), в директорию .ivy2/cache. Оттуда они
        загружается в нашу lib папку проекта. При следующей компиляции проекта  
        сначало будет просмотрен наш кеш на наличие загруженных артифактов(java библиотек)
        и соответственно с репозитария Maven'a ни чего не загрузится что приведет к боллее быстрой
        компиляции и выполнению проекта.
    </target>    
    

    <!-- ================================= 
          target: run сдесь собирается и выполняется наш проект.
         ================================= -->
    <target name="run" depends="resolve" description="--> compile and run the project">
        <mkdir dir="${build.dir}" />
        <javac srcdir="${src.dir}" destdir="${build.dir}" classpathref="lib.path.id" />
     <property name="msg" value="hello ivy !"/>
        <java classpathref="run.path.id" classname="example.Hello">
         <arg value="-message"/>
         <arg value="${msg}"/>
     </java>
    </target>

</project>

В качестве cache у Ivy используется один единственный .ivy2/сache по умолчанию и один единственный - публичный ibiblio resolver. Сдесь я ввел новое понятие - resolver место от куда мы загружаем наши артифакты, мы можем организовывать цепочку (chain) из resolver'ов: заглянем  в проект chained-resolvers/settings/ivysettings.xml:
<ivysettings>
  <settings defaultResolver="chain-example"/>
  <resolvers>
    <chain name="chain-example"> - наша цепочка - объявление
      <filesystem name="libraries"> - сначало ищем артифакты в файловой системе
        <artifact pattern="${ivy.settings.dir}/repository/[artifact]-[revision].[ext]" />
      </filesystem>
      <ibiblio name="ibiblio" m2compatible="true" /> - потом обрашаемся к Maven ibiblio
    </chain>
  </resolvers>
</ivysettings>
Существуют различные resolver'ы способные загружать артифакты не только с web-серверов, но и ssh, ftp, smb, webdav и других, полный список смотрите в документации. Так вернемся к нашим баранам нам осталось только запустить  наш проект на выполнение. Сразу предупрежу если вы выходите в интернет через proxy-server то вам нужно настроить соединение для Ivy установите переменную окружения:
 ANT_OPTS=-Dhttp.proxyHost=myproxyhost -Dhttp.proxyPort=8080 -Dhttp.proxyUserName=myproxyusername -Dhttp.proxyPassword=myproxypassword -Dhttps.proxyHost=myproxyhost -Dhttps.proxyPort=8080
Кратко о главном - как использовать Ivy с Ant для этого нам надо:
  1. Описать артефакты, необходимые для сборки проекта (файл ivy.xml)
  2. Описать репозитории - цепочки (chain), из которых эти артефакты можно получить (файл ivysettings.xml)
  3. Описать в Ant - build.xml вызов задач Ivy.

JSF Spring совместное ипользование.

В свое время я не нашел в интернете простого примера как связать JSF и Spring. Давайте напишем вместе простое hello world - приложение, оно будет состоять из 2 - объектов, 1-й helloWorldMessage - создается spring'om  и вставляется в jsf-объект helloWorld. Для связки 2-х технологий нужно только правильно настроить файлы конфигураций JSF и Spring. Нам понадобится - Apace Tomcat, набор библиотек jsf1.2, набор библиотек spring-framework-2.5.5:
 commons-codec.jar
 commons-logging.jar
 jsf-api.jar
 jsf-impl.jar
 jstl.jar
 jtds-1.2.4.jar
 spring-security-core-2.0.4.jar
 spring-webmvc.jar
 spring.jar
 standard.jar 

Первое нам надо, добавить org.springframework.web.context.ContextLoaderListener в  web.xml файл настройки, для того чтобы включить механизм Dependency Injection - spring'a.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">  
 
  <!-- настраиваем spring для работы -->
    <listener>
      <listener-class>
        org.springframework.web.context.ContextLoaderListener
      </listener-class>
    </listener>

 <!-- обработчик  jsf -->
    <servlet>
      <servlet-name>faces</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>faces</servlet-name>
      <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
    <!-- welcome-file  -->
    <welcome-file-list>
         <welcome-file>index.jsp</welcome-file>
     </welcome-file-list>
</web-app>

По умолчанию будем использовать файл настройки spring - applicationContext.xml для конфигурирования наших bean's:
 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
    <!-- создаем bean c именем helloWorldMessage и устанавливаем его свойство message равным Hello World! Vit -->
    <bean id="helloWorldClass" class="com.vit.HelloWolrd" >
     <property name="message" value="Hello World! Vit" />
    </bean>
</beans>
Ниже привожу код объекта создаваемого spring'om:
 
package com.vit;

public class HelloWorld  {
    // наше свойство устанавливаемое spring
    private String message; 

    public HelloWorld() {
    }
    
    public String getMessage() {
        return message;
    }
    // метод вызываемый spring  при установке свойства message
    public void setMessage(String message) {
        this.message = message;
    }
}
Настроим jsf - нам нужно определить наш jsf bean делается это все в файле faces-config.xml:
 
<faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd" version="1.2">
    <!-- нужно вставить обработчик который передает jsf-контексту, bean'ы созданные spring'om-->
    <application>
      <variable-resolver>
        org.springframework.web.jsf.DelegatingVariableResolver
      </variable-resolver>
    </application>

    <managed-bean>
        <managed-bean-name>helloWorld</managed-bean-name>
        <managed-bean-class>
            com.jsf.HelloWorldJSF
        </managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
            <property-name>hello</property-name>
            <!-- вставляем наш созданный sprin'om объект helloWorldMessage в jsf-объект класса HelloWorldJSF -->
            <value>#{helloWorldClass}</value>
        </managed-property>
    </managed-bean>
</faces-config>
Ниже привожу код класса создаваемого jsf:
 
package com.jsf;

import com.vit.HelloWolrd;

public class HelloWorldJSF {
    //свойство куда вставляется helloWorldClass-объект
    //который любезно создан sprin'om 
    HelloWolrd hello;

    public HelloWolrd getHello() {
        return hello;
    }

    public void setHello(HelloWolrd hello) {
        this.hello = hello;
    }
}
На страничке index.jsp мы переадресуем наш запрос(request) нашей jsf - страничке:
 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <META HTTP-EQUIV="Refresh" CONTENT="0;URL=success.faces">
</head>
<body>
<p>Loading ...</p>
</body>
</html>
страничка success.jsp:
 
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core" %>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Hello World</title>
</head>
<body>
<f:view>
    <h:outputLabel>The message:</h:outputLabel>
    <h:outputText value="#{helloWorld.hello.message}" />
</f:view>
</br>
 Сдесь мы перемещаемся по свойствам объектов(helloWorld.hello.message) и выводим  сообщение  The message:Hello World! Vit 
</body>
</html>
Вот и все!