In my application, I need to use pure JDBC together with Guice. However, Guice doesn't provide any built-in support to manage transactions. guice-persist only provides support based on JPA, which I cannot use.
so I tried to implement a simple solution to manage transactions with Guice and JDBC. here is the first version:
use TransactionHolder to store the transaction per thread.
public class JdbcTransactionHolder {
private static ThreadLocal<JdbcTransaction> currentTransaction = new ThreadLocal<JdbcTransaction>();
public static void setCurrentTransaction(JdbcTransaction transaction) {
currentTransaction.set(transaction);
}
public static JdbcTransaction getCurrentTransaction() {
return currentTransaction.get();
}
public static void removeCurrentTransaction() {
currentTransaction.remove();
}
}
implements a transaction manager for JDBC, for now only begin(), getTransaction(), commit() and rollback() method:
public class JdbcTransactionManager implements TransactionManager {
#Inject
private DataSource dataSource;
#Override
public void begin() throws NotSupportedException, SystemException {
logger.debug("Start the transaction");
try {
JdbcTransaction tran = JdbcTransactionHolder.getCurrentTransaction();
Connection conn = null;
if(tran == null) {
conn = dataSource.getConnection();
}
else {
conn = tran.getConnection();
}
// We have to put the connection in the holder so that we can get later
// from the holder and use it in the same thread
logger.debug("Save the transaction for thread: {}.", Thread.currentThread());
JdbcTransactionHolder.setCurrentTransaction(new JdbcTransaction(conn));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
public void commit() throws RollbackException, HeuristicMixedException,
HeuristicRollbackException, SecurityException,
IllegalStateException, SystemException {
logger.debug("Commit the transaction");
try {
logger.debug("Get the connection for thread: {}.", Thread.currentThread());
Transaction transaction = JdbcTransactionHolder.getCurrentTransaction();
transaction.commit();
}
catch(Exception e) {
throw new RuntimeException(e);
}
finally {
JdbcTransactionHolder.removeCurrentTransaction();
}
}
#Override
public Transaction getTransaction() throws SystemException {
logger.debug("Get transaction.");
final JdbcTransaction tran = JdbcTransactionHolder.getCurrentTransaction();
if(tran == null) {
throw new DBException("No transaction is availble. TransactionManager.begin() is probably not yet called.");
}
return tran;
}
#Override
public void rollback() throws IllegalStateException, SecurityException,
SystemException {
logger.debug("Rollback the transaction");
try {
logger.debug("Get the transaction for thread: {}.", Thread.currentThread());
Transaction conn = JdbcTransactionHolder.getCurrentTransaction();
conn.commit();
}
catch(Exception e) {
throw new RuntimeException(e);
}
finally {
JdbcTransactionHolder.removeCurrentTransaction();
}
}
}
implement a wrapper for DataSource which can get the current connection from the transaction holder if a transaction has been started:
public class JdbcDataSource implements DataSource {
private final static org.slf4j.Logger logger = LoggerFactory.getLogger(JdbcDataSource.class);
private DataSource dataSource;
public JdbcDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
#Override
public PrintWriter getLogWriter() throws SQLException {
return dataSource.getLogWriter();
}
#Override
public int getLoginTimeout() throws SQLException {
return dataSource.getLoginTimeout();
}
#Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return dataSource.getParentLogger();
}
#Override
public void setLogWriter(PrintWriter out) throws SQLException {
this.dataSource.setLogWriter(out);
}
#Override
public void setLoginTimeout(int seconds) throws SQLException {
this.dataSource.setLoginTimeout(seconds);
}
#Override
public boolean isWrapperFor(Class<?> arg0) throws SQLException {
return this.isWrapperFor(arg0);
}
#Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return this.unwrap(iface);
}
#Override
public Connection getConnection() throws SQLException {
JdbcTransaction transaction = JdbcTransactionHolder.getCurrentTransaction();
if(transaction != null) {
// we get the connection from the transaction
logger.debug("Transaction exists for the thread: {}.", Thread.currentThread());
return transaction.getConnection();
}
Connection conn = this.dataSource.getConnection();
conn.setAutoCommit(false);
return conn;
}
#Override
public Connection getConnection(String username, String password)
throws SQLException {
JdbcTransaction transaction = JdbcTransactionHolder.getCurrentTransaction();
if(transaction != null) {
// we get the connection from the transaction
logger.debug("Transaction exists for the thread: {}.", Thread.currentThread());
return transaction.getConnection();
}
return this.dataSource.getConnection(username, password);
}
}
then create a DataSourceProvider so that we can inject DataSource to any POJO using guice:
public class DataSourceProvider implements Provider {
private static final Logger logger = LoggerFactory.getLogger(DataSourceProvider.class);
private DataSource dataSource;
public DataSourceProvider() {
JdbcConfig config = getConfig();
ComboPooledDataSource pooledDataSource = new ComboPooledDataSource();
try {
pooledDataSource.setDriverClass(config.getDriver());
} catch (Exception e) {
throw new RuntimeException(e);
}
pooledDataSource.setJdbcUrl(config.getUrl());
pooledDataSource.setUser(config.getUsername());
pooledDataSource.setPassword(config.getPassword() );
pooledDataSource.setMinPoolSize(config.getMinPoolSize());
pooledDataSource.setAcquireIncrement(5);
pooledDataSource.setMaxPoolSize(config.getMaxPoolSize());
pooledDataSource.setMaxStatements(config.getMaxStatementSize());
pooledDataSource.setAutoCommitOnClose(false);
this.dataSource = new JdbcDataSource(pooledDataSource);
}
private JdbcConfig getConfig() {
JdbcConfig config = new JdbcConfig();
Properties prop = new Properties();
try {
//load a properties file from class path, inside static method
prop.load(JdbcConfig.class.getResourceAsStream("/database.properties"));
//get the property value and print it out
config.setDriver(prop.getProperty("driver"));
config.setUrl(prop.getProperty("url"));
config.setUsername(prop.getProperty("username"));
config.setPassword(prop.getProperty("password"));
String maxPoolSize = prop.getProperty("maxPoolSize");
if(maxPoolSize != null) {
config.setMaxPoolSize(Integer.parseInt(maxPoolSize));
}
String maxStatementSize = prop.getProperty("maxStatementSize");
if(maxStatementSize != null) {
config.setMaxStatementSize(Integer.parseInt(maxStatementSize));
}
String minPoolSize = prop.getProperty("minPoolSize");
if(minPoolSize != null) {
config.setMinPoolSize(Integer.parseInt(minPoolSize));
}
}
catch (Exception ex) {
logger.error("Failed to load the config file!", ex);
throw new DBException("Cannot read the config file: database.properties. Please make sure the file is present in classpath.", ex);
}
return config;
}
#Override
public DataSource get() {
return dataSource;
}
and then implement TransactionalMethodInterceptor to manage the transaction for the method with Transactional annotation:
public class TransactionalMethodInterceptor implements MethodInterceptor {
private final static Logger logger = LoggerFactory.getLogger(TransactionalMethodInterceptor.class);
#Inject
private JdbcTransactionManager transactionManager;
#Override
public Object invoke(MethodInvocation method) throws Throwable {
try {
// Start the transaction
transactionManager.begin();
logger.debug("Start to invoke the method: " + method);
Object result = method.proceed();
logger.debug("Finish invoking the method: " + method);
transactionManager.commit();
return result;
} catch (Exception e) {
logger.error("Failed to commit transaction!", e);
try {
transactionManager.rollback();
}
catch(Exception ex) {
logger.warn("Cannot roll back transaction!", ex);
}
throw e;
}
}
}
Finally, the code to put all together so that Guice can inject the instances:
bind(DataSource.class).toProvider(DataSourceProvider.class).in(Scopes.SINGLETON);
bind(TransactionManager.class).to(JdbcTransactionManager.class);
TransactionalMethodInterceptor transactionalMethodInterceptor = new TransactionalMethodInterceptor();
requestInjection(transactionalMethodInterceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(Transactional.class), transactionalMethodInterceptor);
bind(TestDao.class).to(JdbcTestDao.class);
bind(TestService.class).to(TestServiceImpl.class);
I use c3p0 for the datasource pool. so, it works just fine in my test.
I find another related question: Guice, JDBC and managing database connections
but so far I haven't find any similar approach, except something in SpringFramework. but even the implementation in Spring seems quite complex.
I would like to ask if anyone has any suggestion for this solution.
thanks.
Related
I am using Spring Boot and JdbcTemplate in my application. I am trying to implement timeout for select query but its not working.
My query takes more time than timeout time but still its not giving timeout exception.
#Service
#Slf4j
public class SchedulerService
{
#Autowired
UserService userExportService;
#Autowired
private userExportDao userExportDao;
#Value("${queryTest}")
private String queryFetchByExportFlagCustom;
#Scheduled(fixedDelay=10000)
public void triggerUserExport() {
List<UserExportCustom> userList;
try {
userList = userExportDao.findByExportFlag(0, queryFetchByExportFlagCustom);
userExportService.exportUsers(userList, schedulerCount);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Repository
#Slf4j
public class UserExportDao extends JdbcDaoImpl<UserExportCustom, Long>
{
#Autowired
BeanPropertyRowMapper<UserExportCustom> userExportCustomRowMapper;
#Transactional(readOnly = true, timeout = 1)
public List<UserExportCustom> findByExportFlag(Integer exportFlag, String query)
{
List<UserExportCustom> userExportCustomList = null;
try
{
SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("exportFlag", exportFlag, Types.INTEGER);
userExportCustomList = namedParameterJdbcTemplate.query(query, namedParameters,userExportCustomRowMapper);
}
catch (Exception e)
{
e.printStackTrace();
log.error("Error in findByExportFlag: \n" + e);
}
return userExportCustomList;
}
}
public class JdbcDaoImpl<T, ID> implements JdbcDao<T, ID> {
#Autowired
protected JdbcTemplate jdbcTemplate;
#Autowired
protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Override
public List<T> findAll() {
throw new IllegalStateException();
}
#Override
public T save(T api) {
throw new IllegalStateException();
}
#Override
public T update(T api) {
throw new IllegalStateException();
}
#Override
public T saveOrUpdate(T api) {
throw new IllegalStateException();
}
#Override
public T findOne(String unique) {
throw new IllegalStateException();
}
#Override
public T findOneById(ID id) {
throw new IllegalStateException();
}
#Override
public void delete(ID id) {
throw new IllegalStateException();
}
}
If query take more than 1 second than it should give timeout exception but it does not.
try{}catch{} will lead #Transactional to fail ,remove try catch
I am trying to connect to websocket server endpoint using below code but I am not able to resolve container.connectToServer(this, cec, uri); this. This method is not able to take my class as Endpoint class. It's a spring boot project. If I don't pass config then it accepts but then it fails to connect to server and return 401. I have tried many online links but failed to resolve this issue. Need help in how to fix it.
#ClientEndpoint
public class TestClassEndpoint {
private Session userSession = null;
public TestClassEndpoint(URI uri) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
ClientEndpointConfig cec = ClientEndpointConfig.Builder
.create().configurator(new ClientEndpointConfig.Configurator() {
public void beforeRequest(Map<String, List<String>> headers) {
System.out.println("Setting user cookie in beforeRequest ...");
headers.put("Authorization", Arrays.asList("Basic base64encodedString"));
}
}).build();
container.connectToServer(this, cec, uri);
} catch (Exception e) {
e.printStackTrace();
}
}
#OnOpen
public void onOpen(Session session) {
this.userSession = session;
System.out.println("New connection established");
}
#OnMessage
public void onMessage(String message, Session session) {
System.out.println(message);
}
#OnClose
public void onClose(Session userSession, CloseReason reason) {
this.userSession = null;
System.out.println("connection closed");
}
#OnError
public void onError(Throwable t) {
}
private void sendMessage(ByteBuffer buffer) {
this.userSession.getAsyncRemote().sendBinary(buffer);
}
}
Main class
#SpringBootApplication
public class MainApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(TwilioPocApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
URI uri = UriComponentsBuilder.fromUriString("server_url").build().toUri();
new TestClassEndpoint(uri);
}
}
Below is my application class. The flow is like the DEToken class from here and from DEToken I call RestConnection where I have the #retryable method.
#SpringBootApplication
#EnableRetry
public class SpringBootTrfficApplication implements CommandLineRunner {
Enter code here
#Autowired
DEToken deToken;
#Autowired
SyncService syncService;
public static void main(String[] args) {
SpringApplication.run(SpringBootTrfficApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
deToken.getToken();
}
}
DEToken class: from getToken I am calling RestConnect where I have the #Retrable method:
#Service
public class DEToken {
private Logger logger = LogManager.getLogger(getClass());
#Autowired
RestConnection restConnection;
#Autowired
private Environment env;
public String accessToken;
public void getToken() {
System.out.println("hello from get token");
//String getJsonPayload = "{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
//env.getProperty("provider.ins") + "}}}";
//String str = restConnection.restPost(
// env.getProperty("rest.de.url"), getJsonPayload);
try {
String getJsonPayload =
"{\"Query\":{\"RegisterExtensionWithDE\":{\"pid\": \"\",\"providerInsName\":" +
env.getProperty("provider.ins") + "}}}";
StringBuffer tokenResult =
restConnection.restPost(env.getProperty("rest.de.url"),
getJsonPayload);
System.out.println(tokenResult);
JSONObject xmlJSONObj = XML.toJSONObject(tokenResult.toString());
JSONObject registration = new JSONObject();
if (xmlJSONObj.has("Registration")) {
registration = xmlJSONObj.getJSONObject("Registration");
if (registration.has("accessToken")) {
accessToken = registration.get("accessToken").toString();
}
else
logger.info("no accessToken from DE");
}
else
logger.info("no Registration object from DE");
}
catch (Exception e) {
logger.error("Exception while fetching accesstoken from DE ");
logger.error(e.getMessage());
}
}
}
My REST connection class where I have retryable method:
#Service
public class RestConnection {
private Logger logger = LogManager.getLogger(getClass());
#Autowired
private Environment env;
public void setBaseUrl(String value, String ip) {
//baseUrl = value;
HttpsURLConnection.setDefaultHostnameVerifier(
(hostname, session) -> hostname.equals(ip));
}
/*
* REST post call
*/
#Retryable(value = {IOException.class, ConnectException.class},
maxAttempts = 4,
backoff = #Backoff(5000))
public StringBuffer restPost(String restUrl, String payload) {
StringBuffer sb = new StringBuffer();
HttpURLConnection conn = null;
try {
URL url = new URL(restUrl);
String protocol = url.getProtocol();
if (protocol.toLowerCase().equals("http")) {
conn = (HttpURLConnection)url.openConnection();
}
else if (protocol.toLowerCase().equals("https")) {
//setTrustedCert();
conn = (HttpsURLConnection)url.openConnection();
}
else {
logger.info("Protocol is neither HTTP nor HTTPS");
}
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("version", env.getProperty("de.version"));
conn.setRequestProperty("accessToken", env.getProperty("access.token"));
conn.setRequestProperty("requestHost", env.getProperty("server.de.host"));
conn.setRequestProperty("requestPort", env.getProperty("server.port"));
conn.setRequestProperty("requestProtocol",
env.getProperty("server.de.protocol"));
PrintWriter pout =
new PrintWriter(
new OutputStreamWriter(
conn.getOutputStream(), "UTF-8"),
true);
pout.print(payload);
pout.flush();
pout.close();
InputStream isi = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(isi);
int numCharsRead1;
char[] charArray1 = new char[1024];
while ((numCharsRead1 = isr.read(charArray1)) > 0) {
sb.append(charArray1, 0, numCharsRead1);
}
isr.close();
isi.close();
}
catch (MalformedURLException e) {
logger.error("MalformedURLException in restAccessTokenPOST..." +
e.getMessage());
//e.printStackTrace();
}
catch (IOException e) {
logger.error("IOException in restAccessTokenPOST..." +
e.getMessage());
e.printStackTrace();
}
catch (Exception e) {
logger.error("Exception in restAccessTokenPOST..." +
e.getMessage());
e.printStackTrace();
}
finally {
if (null != conn)
conn.disconnect();
}
return sb;
}
#Recover
public String helpHere(ConnectException cause) {
System.out.println("Recovery place! ConnectException");
return "Hello";
}
#Recover
public String helpHere(IOException cause) {
System.out.println("Recovery place! ArithmeticException");
return "Hello";
}
#Recover
public String helpHere(Exception cause) {
System.out.println("Recovery place! Exception");
return "Hello";
}
#Recover
public String helpHere() {
System.out.println("Recovery place! Exception");
return "Hello";
}
#Recover
public String helpHere(Throwable cause) {
System.out.println("Recovery place! Throwable");
return "Hello";
}
}
Considering you see your function restPost() implementation,
#Retryable(value = {IOException.class, ConnectException.class},
maxAttempts = 4,
backoff = #Backoff(5000))
public StringBuffer restPost(String restUrl, String payload) {
try {
// Your code
}
catch(IOException ex){ // These catch block handles the exception
// and nothing to throw to retryable.
}
catch(MalformedURLException ex){ // More catch blocks that you
// define to handle exception.
}
}
Here you handle all of the exceptions that can be a cause to revoke the retry and recover methods.
Note: Recoverable methods only execute when a exception is thrown, not handled by any try-catch block.
Whatever exception is raised by method restPost() is handled by the method try-catch block itself and there are no exceptions that had been rethrow by a catch block.
Now, Spring-Retry is unable to get any exception (because it is handled by the method try-catch block). So, no recovery method will be executed.
Solution: you should remove those catch blocks from the method definition on which you want to perform retry or recover.
Please do the needful and it will work like a charm... :)
I want to write Junit UT case for my websocket serverendpoint code using embedded Jetty.
i tried things explained in below link:
JUnit test with javax.websocket on embedded Jetty throws RejectedExecutionException: NonBlockingThread
I want to test my onMessage callback for websocket.
If i dont use server.join() method then the connection closes as soon as it opens.
If i use server.join() method nothing happens after joining.
Below is My code.
Server startup code::
public class EmbeddedJettyServer {
private final int port;
private Server server;
public EmbeddedJettyServer(int port) {
this.port = port;
}
public void start() throws Exception {
server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(8080);
server.addConnector(connector);
// Setup the basic application "context" for this application at "/"
// This is also known as the handler tree (in jetty speak)
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
try {
// Initialize javax.websocket layer
ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);
// Add WebSocket endpoint to javax.websocket layer
wscontainer.addEndpoint(WebSocketServer.class);
System.out.println("Begin start");
server.start();
server.dump(System.err);
server.join();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
public void stop() throws Exception {
server.stop();
LOGGER.info("Jetty server stopped");
}
public URI getWebsocketUri(Class<WebSocketServer> class1) {
return server.getURI();
}
}
Client Code:
#ClientEndpoint()
public class WebSocketClientJetty {
WebSocketContainer container;
public Session connect(URI uri) throws Exception {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
// Attempt Connect
Session session = container.connectToServer(WebSocketClientJetty.class,uri);
// return container.connectToServer(WebSocketClientJetty.class, uri);
session.getBasicRemote().sendText("Hello");
// Close session
// session.close();
return session;
} finally {
}
}
public void stop() throws Exception{
if (container instanceof LifeCycle) {
((LifeCycle) container).stop();
}
}
#OnOpen
public void onWebSocketConnect(Session sess)
{
System.out.println("Socket Connected: " + sess);
}
#OnMessage
public void onWebSocketText(String message)
{
System.out.println("Received TEXT message: " + message);
}
#OnClose
public void onWebSocketClose(CloseReason reason)
{
System.out.println("Socket Closed: " + reason);
}
#OnError
public void onWebSocketError(Throwable cause)
{
cause.printStackTrace(System.err);
}
}
Serverendpoint code:
#ServerEndpoint(value = "/echo",
encoders={JsonEncoder.class})
public class WebSocketServer {
private static final Logger LOGGER =
#OnOpen
public void onOpen(Session session){
System.out.println("onopen");
some code....
}
#OnMessage
public void onMessage(String message, Session session) throws IOException{
System.out.println("onmessage");
....
}
#OnClose
public void onClose(Session session){
System.out.println("onClose");
...
}
}
Ut case:
public class WebSocketJettyTest {
private static EmbeddedJettyServer server;
#ClassRule
public static final ExternalResource integrationServer = new ExternalResource() {
#Override
protected void before() throws Throwable {
System.out.println("Starting...");
server = new EmbeddedJettyServer(8080);
server.start();
System.out.println("Started");
}
};
#Before
public void setUp() throws Exception {
}
#After
public void shutdown() throws Exception {
server.stop();
}
#Test
public void testSocket() throws Exception {
/*URI uri = server.getWebsocketUri(WebSocketServer.class);*/
URI uri = URI.create("ws://localhost:8080/echo");
WebSocketClientJetty client = new WebSocketClientJetty();
Session session = client.connect(uri);
session.getBasicRemote().sendText("hello");
Thread.sleep(6000);
client.stop();
}
}
Drop the call to
server.join();
That just makes the current thread wait until the server thread stops.
Which is making it difficult for you.
I really need your help. I have a JDBC code that calls an oracle stored procedure. This is the class that has the code:
public class DAOImpl {
private String sql = "{call MAIN.SP_CALC(?,?,?,?,?)}";
private Connection conn = null;
public DAOImpl(Connection conn) {
this.conn = conn;
}
#Override
public synchronized void executeSP(String year, String month, Long id) throws SQLException {
try (CallableStatement cs = conn.prepareCall(sql);) {
cs.setObject(1, id);
cs.setObject(2, year);
cs.setObject(3, month);
cs.setObject(4, 0);
cs.registerOutParameter(5, Types.INTEGER);
cs.execute();
}
}
}
I have two clients for this class, a JavaSE Tester class and a stateless EJB. The JavaSE main() method have this code:
try {
DriverManager.registerDriver(new OracleDriver());
Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
DAOImpl dao = new DAOImpl(conn);
dao.executeSP("2015", "02", 99561010l);
} catch (SQLException ex) {
Logger.getLogger(SPTester.class.getName()).log(Level.SEVERE, null, ex);
}
The stateless EJB has this other code:
try {
conn = ds.getConnection();
DAO dao = DAOImpl(conn);
dao.executeSP("2015", "02", 99561010l);
} catch (SQLException ex) {
throw new SQLException(ex);
} finally {
conn.close();
}
ds is an instance variable injected to the EJB as a DataSource that comes from a JDBC Connection Pool declared in glassfish of type oracle.jdbc.xa.client.OracleXADataSource. The variables DB_URL, USER, PASS of the JavaSE programm, have the same values that use the JDBC Connection Pool
As you'll notice, the only difference is the Connection object. Both JavaSE and EJB use the ojdbc6.jar driver. Both uses java 1.7.0_u2, that's why I use try-with-resources.
The problem is that only the JavaSE works! Both of them returns after some seconds of processing but only the JavaSE programm works. I have tried many things.. CMT and BMT EJB, wrapped and unwrapped types of id, synchronize and unsynchronize method, etc. I need this code working in the EJB :(
What's the wrong with my EJB?
thanks in advance
This is the CMT version of the EJB
#Stateless
#LocalBean
#Interceptors({PropagateSessionContextInterceptor.class})
public class CalcBean extends BaseContextSessionBean {
#Resource(mappedName = "jdbc/maestro")
protected DataSource ds;
public Connection conn = null;
public void executeSP(String year, String month, Long id) throws SQLException {
try {
conn = ds.getConnection();
DAO dao = DAOImpl(conn);
dao.executeSP("2015", "02", 99561010l);
} catch (SQLException ex) {
throw new SQLException(ex);
} finally {
conn.close();
}
}
}
This is the BMT version of the EJB
#Stateless
#LocalBean
#Interceptors({PropagateSessionContextInterceptor.class})
#TransactionManagement(TransactionManagementType.BEAN)
public class CalcBean extends BaseContextSessionBean {
#Resource(mappedName = "jdbc/maestro")
protected DataSource ds;
public Connection conn = null;
#Resource
UserTransaction tx;
public void executeSP(String year, String month, Long id) throws SQLException {
try {
try {
tx.begin();
conn = ds.getConnection();
DAO dao = DAOImpl(conn);
dao.executeSP("2015", "02", 99561010l);
tx.commit();
} catch (SQLException ex) {
throw new SQLException(ex);
} finally {
conn.close();
}
} catch (Exception e) {
throw new EJBException(e);
}
}
}
public class BaseContextSessionBean {
#Resource
public SessionContext ctx;
}
public class PropagateSessionContextInterceptor {
#AroundInvoke
public Object myInterceptor(InvocationContext ctx) throws Exception
{
BaseContextSessionBean sb = (BaseContextSessionBean)ctx.getTarget();
ControlListener.setSessionContext(sb.ctx);
Object o = ctx.proceed();
return o;
}
}
public interface DAO {
public void executeSP(String year, String month, Long id) throws SQLException;
}
I don't know the reason of BaseContextSessionBean and PropagateSessionContextInterceptor. Originally, the EJB used a useless JDBC framework (that uses those classes), so I replaced it with the DAOImpl class. I use a DAO interface to decouple the implementation, the DaoImpl is been execute (in the EJB, the DAOImpl implements DAO, I forgot to put that in the earlier post)