`
whitesock
  • 浏览: 483756 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

OpenEJB (2)

    博客分类:
  • EE
阅读更多

本文部分内容节选自Enterprise JavaBeans 3.0 by Bill Burke & Richard Monson-Haefel

 

3 Injection
    每个部署于应用服务器中的EJB容器都拥有一个属于它自己的内部注册表(internal registry),该内部注册表被成为Enterprise Naming Context(ENC)。EJB容器可以在其中维护某些指向外部环境资源的引用。可以通过annotation和XML文件配置ENC。可以绑定到ENC中的内容有:EJB接口、EntityManagerFactory、EntityManager、DataSource、JMS Destination、TimeService、UserTransaction和Environment Entry等。



3.1 Injection of EJBs
    以下是个关于Injection of EJBs的简单例子:

public interface DataStore {
	
	String getData();
	
}
import javax.ejb.Local;

@Local
public interface DataStoreLocal extends DataStore {
}
import javax.ejb.Remote;

@Remote
public interface DataStoreRemote extends DataStore {
}
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class DataStoreImpl implements DataStoreLocal, DataStoreRemote {

	public String getData() {
		return "data";
	}

}
import javax.ejb.Local;

@Local
public interface DataReaderLocal {
	
	String readLocalData();
	
}
import javax.ejb.Remote;

@Remote
public interface DataReaderRemote {
	
	String readRemoteData();
	
}
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class DataReaderImpl implements DataReaderLocal, DataReaderRemote {
	@EJB(name="DataStoreLocal")
	private DataStoreLocal dataStoreLocal;
	
	@EJB(name="DataStoreRemote")
	private DataStoreRemote dataStoreRemote;

	public String readLocalData() {
		return "Local " + dataStoreLocal.getData();
	}

	public String readRemoteData() {
		return "Remote " + dataStoreRemote.getData();
	}
}
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

public class InjectionTest {
	public static void main(String args[]) throws Exception {
		//
		Properties properties = new Properties();
		properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
		InitialContext ctx = new InitialContext(properties);
		
		// 
		DataReaderLocal drl = (DataReaderLocal)ctx.lookup("DataReaderImplLocal");
		System.out.println(drl.readLocalData());
		
		//
		Object ref = ctx.lookup("DataReaderImplRemote");
		DataReaderRemote drr = (DataReaderRemote) PortableRemoteObject.narrow(ref, DataReaderRemote.class);
		System.out.println(drr.readRemoteData());
	}
}

    任何注册到ENC中的内容都可以在java:comp/env上下文中通过名称查找。SessionContext和MessageDrivenContext接口都继承自EJBContext。EJBContext接口中有个便捷方法用于JNDI查找,它不抛出检查式异常,而且用的是相对于ENC的内部名称,而不是之前提到的java:comp/env全名。以下是个简单的例子:

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.EJBs;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

@Stateless
@EJBs ({
	@EJB(name="DataStoreLocal", beanInterface=DataStoreLocal.class),
	@EJB(name="DataStoreRemote", beanInterface=DataStoreRemote.class)
})
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class DataReaderImpl implements DataReaderLocal, DataReaderRemote {
	@Resource
	private SessionContext context;
	
	public String readLocalData() {
		//
		DataStoreLocal dsl = null;
		try {
			InitialContext ctx = new InitialContext();
			dsl = (DataStoreLocal)ctx.lookup("java:comp/env/DataStoreLocal");
		} catch (NamingException e) {
			throw new RuntimeException("failed to lookup DataStoreLocal", e);
		}
		
		//
		return "Local " + dsl.getData();
	}

	public String readRemoteData() {
		Object ref = context.lookup("DataStoreRemote");
		DataStoreRemote dsr = (DataStoreRemote)PortableRemoteObject.narrow(ref, DataStoreRemote.class);
		return "Remote " + dsr.getData();
	}
}

 

3.2 Injection of DataSource
    以下是个关于Injection of DataSource的简单例子:

import java.io.Serializable;

import javax.persistence.Basic;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Movie implements Serializable {
	//
	private static final long serialVersionUID = -3282817754636291024L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;
	
	@Basic
	private String title;
	
	@Basic
	private String director;
	
	@Basic
	private int year;

	public Movie() {
	}
	
	public Movie(String title, String director, int year) {
		this.title = title;
		this.director = director;
		this.year = year;
	}
	
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("id: " + id);
		sb.append(", title: " + title);
		sb.append(", director: " + director);
		sb.append(", year: " + year);
		return sb.toString();
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getDirector() {
		return director;
	}
	
	public void setDirector(String director) {
		this.director = director;
	}
	
	public int getYear() {
		return year;
	}
	
	public void setYear(int year) {
		this.year = year;
	}
}
import java.util.List;

public interface MovieDao {
	
	List<Movie> getAllMovies();
	
	void addMovies(List<Movie> movies);
	
	void deleteMovie(Movie movie);
}
import javax.ejb.Local;

@Local
public interface MovieDaoJdbcLocal extends MovieDao {
}
import javax.ejb.Remote;

@Remote
public interface MovieDaoJdbcRemote extends MovieDao {
}
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.sql.DataSource;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class MovieDaoJdbcImpl implements MovieDaoJdbcLocal, MovieDaoJdbcRemote {
	
	@Resource(name="mysqlDataSource")
    private DataSource mysql;
	
	public List<Movie> getAllMovies() {
		ArrayList<Movie> movies = new ArrayList<Movie>();
        try {
        	Connection con = mysql.getConnection();
            PreparedStatement stmt = con.prepareStatement("SELECT id, director, title, year FROM movie");
            ResultSet rs = stmt.executeQuery();
            while ( rs.next() ) {
                Movie movie = new Movie();
                movie.setId(rs.getInt("id"));
                movie.setDirector(rs.getString("director"));
                movie.setTitle(rs.getString("title"));
                movie.setYear(rs.getInt("year"));
                movies.add(movie);
            }
            rs.close();
            stmt.close();
            con.close();
        } catch(SQLException e) {
        	throw new RuntimeException(e);
        }
        return movies;
	}
	
	public void addMovies(List<Movie> movies) {
        try {
        	Connection con = mysql.getConnection();
        	for(Movie movie : movies) {
        		PreparedStatement stmt = con.prepareStatement("INSERT INTO movie (director, title, year) VALUES (?, ?, ?)");
                stmt.setString(1, movie.getDirector());
                stmt.setString(2, movie.getTitle());
                stmt.setInt(3, movie.getYear());
                stmt.execute();
                stmt.close();
        	}
        	con.close();
        } catch(SQLException e) {
        	throw new RuntimeException(e);
        }
	}

	public void deleteMovie(Movie m) {
        try {
        	Connection con = mysql.getConnection();
        	PreparedStatement stmt = con.prepareStatement("DELETE FROM movie WHERE id = ?");
        	stmt.setInt(1, m.getId());
        	stmt.executeUpdate();
        	stmt.close();
        	con.close();
        } catch(SQLException e) {
        	throw new RuntimeException(e);
        }
	}
}

    OpenEJB可以通过JNDI Context的properties定义DataSource,例如:

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

public class InjectionOfDataSourceTest {
	
	public static void main(String args[]) throws Exception {
		//
		Properties properties = new Properties();
		properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
		properties.put("mysqlDataSource", "new://Resource?type=DataSource");
		properties.put("mysqlDataSource.JdbcDriver", "com.mysql.jdbc.Driver");
		properties.put("mysqlDataSource.JdbcUrl", "jdbc:mysql://localhost:3306/ejb");
		properties.put("mysqlDataSource.username", "root");
		properties.put("mysqlDataSource.password", "password");
		properties.put("mysqlDataSourceUnmanaged.JtaManaged", "true");
		InitialContext ctx = new InitialContext(properties);
		
		// 
		List<Movie> movies = new ArrayList<Movie>();
		movies.add(new Movie("Dances with Wolves", "Kevin Costner", 1990));
		movies.add(new Movie("Legends of the Fall", "Edward Zwich", 1994));
		movies.add(new Movie("A Very Long Engagement", "Jean-Pierre Jeunet", 2004));
		
		//
		Object ref1 = ctx.lookup("MovieDaoJdbcImplRemote");
		MovieDaoJdbcRemote dao1 = (MovieDaoJdbcRemote) PortableRemoteObject.narrow(ref1, MovieDaoJdbcRemote.class);
		dao1.addMovies(movies);
		for(Movie m : dao1.getAllMovies()) {
			System.out.println("dao1.getAllMovies(): " + m);
			dao1.deleteMovie(m);
		}
	}
}

    此外,也可以在conf/openejb.xml中定义DataSource,例如以下是openejb.xml中的相关配置:

<Resource id="mysqlDataSource" type="DataSource">
  JdbcDriver com.mysql.jdbc.Driver
  JdbcUrl jdbc:mysql://localhost:3306/ejb
  UserName root
  Password password
  JtaManaged true
</Resource>

    目前OpenEJB尚不支持在openejb.xml中,以加密后的形式保存Password,关于详细介绍请参考OpenEJB User Forum。

 

3.3 Injection of EntityManager
    EntityManager可以被注入到EJB中。当你将EntityManager注册到ENC中或者注入到EJB时,EJB容器会对EntityManager所依赖的persistentce context具有完全的控制权。在注入的EntityManager上调用close方法会导致异常。默认的PersistenceContextType是TRANSACTION。EXTENDED类型的persistence context只能用于stateful session bean。META-INF目录下的persistence.xml用以配置JPA。以下是个简单的例子:

import javax.ejb.Local;

@Local
public interface MovieDaoJpaLocal extends MovieDao {
}
import javax.ejb.Remote;

@Remote
public interface MovieDaoJpaRemote extends MovieDao {
}
import java.util.List;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.persistence.Query;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class MovieDaoJpaImpl implements MovieDaoJpaLocal, MovieDaoJpaRemote {
	
	@PersistenceContext(unitName = "ejb", type = PersistenceContextType.TRANSACTION)
	private EntityManager entityManager;
	
	public List<Movie> getAllMovies() {
		Query query = entityManager.createQuery("SELECT m from Movie as m");
        return query.getResultList();
	}
	
	public void addMovies(List<Movie> movies) {
		for(Movie m : movies) {
			entityManager.persist(m);
		}
	}

	public void deleteMovie(Movie movie) {
		Movie m = entityManager.merge(movie);
		entityManager.remove(m);
	}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;

public class InjectionOfEntityManagerTest {
	
	public static void main(String args[]) throws Exception {
		//
		Properties properties = new Properties();
		properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
		properties.put("mysqlDataSource", "new://Resource?type=DataSource");
		properties.put("mysqlDataSource.JdbcDriver", "com.mysql.jdbc.Driver");
		properties.put("mysqlDataSource.JdbcUrl", "jdbc:mysql://localhost:3306/ejb");
		properties.put("mysqlDataSource.username", "root");
		properties.put("mysqlDataSource.password", "password");
		properties.put("mysqlDataSourceUnmanaged.JtaManaged", "true");
		InitialContext ctx = new InitialContext(properties);
		
		// 
		List<Movie> movies = new ArrayList<Movie>();
		movies.add(new Movie("Dances with Wolves", "Kevin Costner", 1990));
		movies.add(new Movie("Legends of the Fall", "Edward Zwich", 1994));
		movies.add(new Movie("A Very Long Engagement", "Jean-Pierre Jeunet", 2004));
		
		//
		Object ref2 = ctx.lookup("MovieDaoJpaImplRemote");
		MovieDaoJpaRemote dao2 = (MovieDaoJpaRemote) PortableRemoteObject.narrow(ref2, MovieDaoJpaRemote.class);
		dao2.addMovies(movies);
		for(Movie m : dao2.getAllMovies()) {
			System.out.println("dao2.getAllMovies(): " + m);
			dao2.deleteMovie(m);
		}
	}
}

    META-INF/ persistence.xml文件的内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    version="1.0">
    
    <persistence-unit name="ejb">
        <jta-data-source>mysqlDataSource</jta-data-source>
        
		<provider>
		    org.apache.openjpa.persistence.PersistenceProviderImpl
		</provider>
		 
		<properties>
		    <property name="openjpa.Log" value="log4j"/>
		    <property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=72"/>
		    <property name="openjpa.jdbc.TransactionIsolation" value="read-committed"/>
		</properties>
		
	</persistence-unit>
</persistence>

 

3.4 Injection of env-entry
    可以通过环境注册项(environment entry)对EJB进行配置。环境注册项不是元数据,而是配置项。EJB3.0规范支持的环境注册项类型如下:

  • java.lang.String
  • java.lang.Integer
  • java.lang.Short
  • java.lang.Float
  • java.lang.Double
  • java.lang.Byte
  • java.lang.Character
  • java.lang.Boolean

    在OpenEJB中并不限于以上类型。如果提供了合适的java.beans.PropertyEditor,那么任何可以从String转换到的类型都被支持。除了在META-INF/ejb-jar.xml中配置环境注册项外,也可以在META-INF/env-entries.properties文件中进行配置。以下是个简单的例子:

import java.beans.PropertyEditorManager;

public enum Fruit {
	//
	APPLE,
    PEACH,
    UNKNOWN;
	
	//
	static {
        PropertyEditorManager.registerEditor(Fruit.class, FruitEditor.class);
    }
}
import java.beans.PropertyEditorSupport;

public class FruitEditor extends PropertyEditorSupport {
	
	public void setAsText(String text) throws IllegalArgumentException {
        text = text.trim();
        if (text.equalsIgnoreCase("APPLE")) {
        	setValue(Fruit.APPLE);
        } else if (text.equalsIgnoreCase("PEACH")) {
        	setValue(Fruit.PEACH);
        } else {
        	setValue(Fruit.UNKNOWN);
        }
    }
}
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.ejb.Local;

@Local
public interface BasketLocal {
	
	int getCount();
	
	Date getDate();

	Fruit getFruit();
	
	List<Fruit> getList();

	Map<Fruit, Float> getMap();
}
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.Stateful;

@Stateful
public class BasketImpl implements BasketLocal {
	@Resource
	private int count;
	
	@Resource(name="date")
	private Date date;
	
	@Resource(name = "fruit")
	private Fruit fruit;
	
	@Resource(name="list")
	private List<Fruit> list;
	
	@Resource
	private Map<Fruit, Float> map;
	
	public int getCount() {
		return count;
	}
	
	public Date getDate() {
		return date;
	}

	public Fruit getFruit() {
		return fruit;
	}

	public List<Fruit> getList() {
		return list;
	}
	
	public Map<Fruit, Float> getMap() {
		return map;
	}
}
import java.util.Iterator;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

public class InjectionOfEnvEntryTest {
	
	public static void main(String args[]) throws Exception {
		//
		Properties properties = new Properties();
		properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
		InitialContext ctx = new InitialContext(properties);
		
		// 
		BasketLocal basket = (BasketLocal)ctx.lookup("BasketImplLocal");
		System.out.println("count: " + basket.getCount());
		System.out.println("date: " + basket.getDate());
		System.out.println("fruit: " + basket.getFruit());
		System.out.print("list: ");
		for(Iterator<Fruit> iter = basket.getList().iterator(); iter.hasNext();) {
			System.out.print(iter.next());
			if(iter.hasNext()) {
				System.out.print(", ");
			}
		}
		System.out.println();
		System.out.print("map: ");
		for(Iterator<Fruit> iter = basket.getMap().keySet().iterator(); iter.hasNext();) {
			Fruit key = iter.next();
			System.out.print(key + "=" + basket.getMap().get(key));
			if(iter.hasNext()) {
				System.out.print(", ");
			}
		}
		System.out.println();
	}
}

    META-INF/env-entries.properties的内容如下:

    date=2008-05-06
    list=APPLE,PEACH,PEACH
    com.yourpackage.BasketImpl/map=APPLE=1.00\nPEACH=2.00\n

    META-INF/ejb-jar.xml的内容如下:

<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" version="3.0" metadata-complete="false">
  
  <enterprise-beans>
    <session>
      <ejb-name>BasketImpl</ejb-name>
      
      <env-entry>
        <description>count</description>
        <env-entry-name>com.yourpackage.BasketImpl/count</env-entry-name>
        <env-entry-type>java.lang.Integer</env-entry-type>
        <env-entry-value>12</env-entry-value>
      </env-entry>
      
      <env-entry>
        <description>fruit</description>
        <env-entry-name>fruit</env-entry-name>
        <env-entry-type>java.lang.String</env-entry-type>
        <env-entry-value>APPLE</env-entry-value>
      </env-entry>
    </session>
  </enterprise-beans>
</ejb-jar>

    需要注意的是,以上例子中BasketImpl的成员变量count和map的@Resource中没有指定name属性,那么默认的ENC名称是:所在类的全限定类名 / 数据成员或方法的基础名。当需要在XML部署描述文件中进行配置时,需要正确使用ENC名。

13
4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics