Extensões para APIs de Acesso a Dados
Se uma única API de acesso a dados não fornecer uma solução completa para seus aplicativos, utilize as extensões do WebSphere Application Server para obter interoperabilidade entre as APIs JCA e JDBC.
Aplicativos extraídos de configurações de gerenciamento de recursos distintas e complexas podem exigir o uso das APIs Java™ Platform, Enterprise Edition (Java EE) Connector Architecture (JCA) e Java Database Connectivity (JDBC). No entanto, em alguns casos, o modelo de programação JDBC não se integra completamente ao JCA (mesmo se a integração total for uma fundação da especificação JCA). Estas inconsistências podem limitar as opções de acesso a dados para um aplicativo que utiliza ambas as APIs. O WebSphere Application Server fornece extensões de API para resolver os problemas de compatibilidade.
Exemplo:
Sem o benefício de uma extensão, os aplicativos que utilizam as APIs não podem modificar as propriedades de uma conexão que pode ser compartilhada após fazer o pedido de conexão, se existirem outros manuseios para esta conexão. (Se nenhum outro manuseio estiver associado à conexão, as propriedades de conexão poderão ser alteradas.) Esta limitação é derivada de uma incompatibilidade entre as políticas de configuração de conexão das APIs:
A especificação de Arquitetura de Conector (JCA) suporta retransmissão para o adaptador de recursos das configurações de propriedades específicas no momento em que você solicita a conexão, utilizando o método getConnection(), transmitindo um objeto ConnectionSpec. O objeto ConnectionSpec contém as propriedades de conexão necessárias utilizadas para obter uma conexão. Depois de obter uma conexão desse ambiente, o aplicativo não necessita alterar as propriedades. O modelo de programação JDBC, no entanto, não possui a mesma interface para especificar as propriedades de conexão. Em vez disso, ele primeiro obtém a conexão e, em seguida, define as propriedades na conexão.
O WebSphere Application Server fornece as seguintes extensões para preencher estas lacunas entre as especificações JDBC e JCA:
- Interface do WSDataSource - esta interface estende a classe javax.sql.DataSource e permite que um componente ou aplicativo especifique as propriedades de conexão por meio da classe do WebSphere Application Server JDBCConnectionSpec para obter uma conexão.
- getConnection(JDBCConnectionSpec) - este método retorna uma conexão com as propriedades especificadas na classe JDBCConnectionSpec.
- Para obter informações adicionais, consulte o tópico da documentação da API WSDataSource (conforme listado no índice da documentação da API).
- Interface JDBCConnectionSpec - essa interface estende a classe com.ibm.websphere.rsadapter.WSConnectionSpec, que estende a classe javax.resources.cci.ConnectionSpec. A interface ConnectionSpec padrão fornece apenas o marcador de interface sem quaisquer métodos get() e set(). As interfaces WSConnectionSpec e JDBCConnectionSpec definem um conjunto de métodos get() e set() utilizados pelo tempo de execução do WebSphere Application Server. Esta interface permite que o aplicativo especifique todas as propriedades essenciais da conexão para obter uma conexão apropriada. É possível criar essa classe a partir da classe WSRRAFactory do WebSphere. Para obter informações adicionais, consulte o tópico de documentação JDBCConnection da API (conforme listado no índice de documentação da API).
- Classe WSRRAFactory - esta é uma classe factory para o WebSphere Relational Resource Adapter, que permite ao usuário criar um objeto JDBCConnectionSpec ou outro objeto relacionado ao adaptador de recursos. Para obter informações adicionais consulte o tópico da documentação da API WSRRAFactory (conforme listado no índice de documentação da API).
- Interface WSConnection - esta é uma interface que permite aos usuários chamar
métodos de propriedade do WebSphere
em conexões SQL; estes métodos são:
- setClientInformation(Properties props) - Consulte o tópico Exemplo: Configurando Informações do Cliente com a API setClientInformation(Properties), para obter informações adicionais e exemplos de configuração de informações do cliente.
- Properties getClientInformation() - Esse método retorna o objeto de propriedades que é definido utilizando setClientInformation(Properties). Observe que o objeto de propriedades retornado não é afetado pelas configurações implícitas das informações do cliente.
- WSSystemMonitor getSystemMonitor() - Este método retorna o objeto
SystemMonitor da conexão de banco de dados de backend se o banco de dados
suportar os Monitores de Sistema. O banco de dados de backend fornecerá algumas estatísticas
de conexão no objeto SystemMonitor. O objeto SystemMonitor retornado é agrupado em um
objeto WebSphere
(com.ibm.websphere.rsadapter.WSSystemMonitor) para proteger os aplicativos contra
dependência de qualquer código de fornecedor de banco de dados.
Consulte a
documentação com.ibm.websphere.rsadapter.WSSystemMonitor Java
para obter informações adicionais. O código a seguir é um exemplo de uso da classe
WSSystemMonitor:
import com.ibm.websphere.rsadapter.WSConnection; ... try{ InitialContext ctx = new InitialContext(); // Executar uma pesquisa no serviço de nomes para obter o objeto DataSource. DataSource ds=(javax.sql.DataSource]ctx.lookup("java:comp/jdbc/myDS"); }catch (Exception e) {;} WSConnection conn=(WSConnection)ds.getConnection(); WSSystemMonitor sysMon=conn.getSystemMonitor(); if (sysMon!=null) // indica que a monitoração do sistema é suportada no banco de dados de backend atual { sysMon.enable(true); sysMon.start(WSSystemMonitor.RESET_TIMES); // interage com o banco de dados sysMon.stop(); // coleta dados do objeto sysMon } conn.close();
A interface WSConnection faz parte do arquivo plugins_root/com.ibm.ws.runtime.jar.
Exemplo: Usando APIs estendidas da IBM para conexões com o banco de dados.
Usando a API estendida WSDataSource, é possível codificar seu aplicativo JDBC para definir as propriedades da conexão por meio de um objeto antes de obter uma conexão. Esse comportamento aumenta as oportunidades de compartilhamento do aplicativo de uma conexão com outro componente, como por exemplo um CMP.
Se o seu aplicativo for executado com uma conexão compartilhável que possa ser compartilhada com outros beans de persistência gerenciada por contêiner (CMP) em uma transação, é recomendável utilizar as APIs estendidas do WebSphere Application Server para obter a conexão. Quando estas APIs são utilizadas, não é possível portar o aplicativo para outros servidores de aplicativos.
É possível codificar com a API estendida diretamente em seu aplicativo JDBC; em vez de utilizar a interface DataSource para obter uma conexão, utilize a interface WSDataSource. O segmento de código a seguir ilustra a interface WSDataSource:
import com.ibm.websphere.rsadapter.*;
...
// Crie uma JDBCConnectionSpec e defina as propriedades da conexão. Se essa conexão
// for compartilhado com o bean CMP, certifique-se de que o nível de isolamento é o mesmo que o
// nível de isolamento mapeado pela Intenção de acesso no bean CMP.
JDBCConnectionSpec connSpec = WSRRAFactory.createJDBCConnectionSpec();
connSpec.setTransactionIsolation(CONNECTION.TRANSACTION_REPEATABLE_READ);
connSpec.setCatalog("DEPT407");
// Usar o WSDataSource para obter a conexão
Connection conn = ((WSDataSource)datasource).getConnection(connSpec);
Exemplo: Usando as APIs Estendidas IBM para Compartilhar Conexões entre Beans CMP e Beans BMP.
Em um componente de aplicativo que acessa dados por meio de objetos JDBC, como um bean de persistência gerenciada por bean (BMP), é possível usar uma API estendida do WebSphere para definir propriedades de conexão através de um objeto antes de obter uma conexão. Esse comportamento aumenta as oportunidades de compartilhamento do bean BMP de uma conexão com um bean CMP (Container-Managed Persistence).
Se o seu bean BMP for executado com uma conexão compartilhável que possa ser compartilhada com outros beans de persistência gerenciada por contêiner (CMP) em uma transação, é recomendável utilizar as APIs estendidas do WebSphere Application Server para obter a conexão. Quando essas APIs são utilizadas, não é possível portar o aplicativo para outros servidores de aplicativos.
Nesse caso, utilize a interface WSDataSource da API estendida, em vez da interface DataSource. Para assegurar que os beans CMP e BMP (Bean-managed Persistence) estejam compartilhando a mesma conexão física, defina o mesmo perfil de intenção de acesso nos beans CMP e BMP. Dentro do método de BMP, é possível obter o nível de isolamento correto a partir da classe auxiliar do adaptador de recursos relacional.
package fvt.example;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.ejb.CreateException;
import javax.ejb.DuplicateKeyException;
import javax.ejb.EJBException;
import javax.ejb.ObjectNotFoundException;
import javax.sql.DataSource;
// as importações a seguir são usadas pela API estendida IBM
import com.ibm.websphere.appprofile.accessintent.AccessIntent;
import com.ibm.websphere.appprofile.accessintent.AccessIntentService;
import com.ibm.websphere.rsadapter.JDBCConnectionSpec;
import com.ibm.websphere.rsadapter.WSCallHelper;
import com.ibm.websphere.rsadapter.WSDataSource;
import com.ibm.websphere.rsadapter.WSRRAFactory;
/**
* Classe de implementação do bean para Enterprise Bean: Simple
*/
public class SimpleBean implements javax.ejb.EntityBean {
private javax.ejb.EntityContext myEntityCtx;
// Contexto inicial utilizado para pesquisa.
private javax.naming.InitialContext ic = null;
// defina uma JDBCConnectionSpec como variável da instância
private JDBCConnectionSpec connSpec;
// defina uma AccessIntentService que é utilizada para obter
// um objeto AccessIntent.
private AccessIntentService aiService;
// objeto AccessIntent utilizado para obter o nível de isolamento
private AccessIntent intent = null;
// Nome da tabela de persistência
private String tableName = "cmtest";
// Nome JNDI do DataSource
private String dsName = "java:comp/env/jdbc/SimpleDS";
// DataSource
private DataSource ds = null;
// variáveis da instância do bean.
private int id;
private String name;
/**
* No método setEntityContext, é necessário obter o objeto AccessIntentService
* para que os métodos subseqüentes obtenham o objeto AccessIntent.
* um objeto String.
* Outros métodos de ejb chamarão o getConnection() privado para obter a
* conexão que tem todas as propriedades de conexão específicas
*/
public void setEntityContext(javax.ejb.EntityContext ctx) {
myEntityCtx = ctx;
try {
aiService =
(AccessIntentService) getInitialContext().lookup(
"java:comp/websphere/AppProfile/AccessIntentService");
ds = (DataSource) getInitialContext().lookup(dsName);
}
catch (javax.naming.NamingException ne) {
throw new javax.ejb.EJBException(
"Naming exception: " + ne.getMessage());
}
}
/**
* ejbCreate
*/
public fvt.example.SimpleKey ejbCreate(int newID)
throws javax.ejb.CreateException, javax.ejb.EJBException {
Connection conn = null;
PreparedStatement ps = null;
// Insira Cadeia SQL
String sql = "INSERT INTO" + tableName + "(id, name) VALUES (?, ?)";
id = newID;
name = "";
try {
// chame o método comum para obter a conexão específica
conn = getConnection();
}
catch (java.sql.SQLException sqle) {
throw new EJBException("SQLException caught: " + sqle.getMessage());
}
catch (javax.resource.ResourceException re) {
throw new EJBException(
"ResourceException caught: " + re.getMessage());
}
try {
ps = conn.prepareStatement(sql);
ps.setInt(1, id);
ps.setString(2, name);
if (ps.executeUpdate() != 1) {
throw new CreateException("Failed to add a row to the DB");
}
}
catch (DuplicateKeyException dke) {
throw new javax.ejb.DuplicateKeyException(
id + "has already existed");
}
catch (SQLException sqle) {
throw new javax.ejb.CreateException(sqle.getMessage());
}
catch (CreateException ce) {
throw ce;
}
finally {
if (ps != null) {
try {
ps.close();
}
catch(Exception e){
}
}
}
return new SimpleKey(id);
}
/**
* ejbLoad
*/
public void ejbLoad() throws javax.ejb.EJBException {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String loadSQL = null;
try {
// chame o método comum para obter a conexão específica
conn = getConnection();
}
catch (java.sql.SQLException sqle) {
throw new EJBException("SQLException caught: " + sqle.getMessage());
}
catch (javax.resource.ResourceException re) {
throw new EJBException(
"ResourceException caught: " + re.getMessage());
}
// É preciso determinar qual instrução select será utilizada com base no
// tipo de AccessIntent:
// Se for READ, utiliza uma instrução SELECT normal. Caso contrário, utiliza
// a instrução SELECT...FORUPDATE
// Se o backend for SQLServer, é possível utilizar sintaxe diferente para
// a cláusula FOR UPDATE.
if (intent.getAccessType() == AccessIntent.ACCESS_TYPE_READ) {
loadSQL = "SELECT * FROM" + tableName + "WHERE id = ?";
}
else {
loadSQL = "SELECT * FROM" + tableName + "WHERE id = ? FOR UPDATE";
}
SimpleKey key = (SimpleKey) getEntityContext().getPrimaryKey();
try {
ps = conn.prepareStatement(loadSQL);
ps.setInt(1, key.id);
rs = ps.executeQuery();
if (rs.next()) {
id = rs.getInt(1);
name = rs.getString(2);
}
else {
throw new EJBException("Cannot load id = " + key.id);
}
}
catch (SQLException sqle) {
throw new EJBException(sqle.getMessage());
}
finally {
try {
if (rs != null)
rs.close();
}
catch(Exception e){
}
try {
if (ps != null)
ps.close();
}
catch(Exception e){
}
try {
if (conn != null)
conn.close();
}
catch(Exception e){
}
}
}
/**
* Este método utilizará o AccessIntentService para obter a intenção de acesso;
* em seguida, obtém o nível de isolamento do DataStoreHelper
* e o define na especicação da conexão; depois utiliza essa especificação da conexão
* para obter uma conexão que tenha as propriedades de conexão
* customizadas.
**/
private Connection getConnection()
throws java.sql.SQLException, javax.resource.ResourceException, EJBException {
// obtenha o objeto de intenção de acesso atual utilizando o contexto de EJB
intent = aiService.getAccessIntent(myEntityCtx);
// Suponha que este bean suporta somente a simultaneidade pessimista
if (intent.getConcurrencyControl()
!= AccessIntent.CONCURRENCY_CONTROL_PESSIMISTIC) {
throw new EJBException("Bean supports only pessimistic concurrency");
}
// determinar o nível de isolamento correto para o banco de dados configurado atualmente
// utilizando DataStoreHelper
int isoLevel =
WSCallHelper.getDataStoreHelper(ds).getIsolationLevel(intent);
connSpec = WSRRAFactory.createJDBCConnectionSpec();
connSpec.setTransactionIsolation(isoLevel);
// Obtenha a conexão utilizando a especificação da conexão
Connection conn = ((WSDataSource) ds).getConnection(connSpec);
return conn;
}