I'm trying to create database connection using Listener and get the connection to Servlet and do some database Query and show output on the browser but output not come to brower.it don't show error just blank page.is my code Wrong(my english pretty bad sorry)
this is Listener
public class Mylistener implements ServletContextListener {
public Mylistener() {
}
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("closed");
ServletContext context = sce.getServletContext();
Connection connection = (Connection) context.getAttribute("conn");
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void contextInitialized(ServletContextEvent sce) {
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:XE","system","manager");
ServletContext context = sce.getServletContext();
context.setAttribute("conn", connection);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
//this is Servlet
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public MyServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response .getWriter();
String tname = request.getParameter("tname");
ServletContext context = request.getServletContext();
Connection connection=(Connection) context.getAttribute("conn");
try
{
Statement statement = connection.createStatement();
ResultSet set = statement.executeQuery("select * from " + tname);//tname pass by html form
while(set.next())
{
writer.println(set.getInt(1)+"...."+set.getString(2)+"...."+set.getDouble(3));
//System.out.println(set.getInt(1)+"...."+set.getString(2)+"...."+set.getDouble(3));
writer.println("<br><br>");
}
}
catch(SQLException e)
{
e.printStackTrace();
}
}
}
Related
I have created an application which reads & writes into a remote file. I have different files (A.properties, B.properties, C.properties) in different directories (folder-1, folder-2, folder-3). Each directory has the same filename with different data.
I have implemented concurrency in my application by using the LockRegistry provided by this other answer. The issue is that if a thread is accessing A.properties while another thread accesses B.properties, the propertyMap displayed to the end user will contain both data from property files. How can I resolve this issue?
My code:
public class UDEManager
{
private Map<String, String> propertyMap = new TreeMap<>();
HttpSession session = null;
public UDEPropertyManager()
{
super();
}
public void init(ServletConfig config) throws ServletException
{
super.init(config);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
// Code for calling thread for read/write operations into remote
// file and fill the propertyMap
}
}
class WebAppProperty implements Runnable
{
private WebApp webapp; // folder-1
private String propertyFile; // A.properties
private String keyValue; //messages-title=Messages
private LockType mode;
public String getPropertyFile()
{
return propertyFile;
}
public void setPropertyFile(String propertyFile)
{
this.propertyFile = propertyFile;
}
#Override
public void run()
{
try {
LockRegistry.INSTANCE.acquire(propertyFile, mode);
if (this.mode == LockType.WRITE) {
writeToPropertyFile();
} else if (this.mode == LockType.READ) {
getProperty(this.webapp, this.propertyFile);
}
} catch (Exception ie) {
sysoutAndLog("Thread is Interrupted");
ie.printStackTrace();
} finally {
LockRegistry.INSTANCE.release(propertyFile, mode);
}
}
private boolean getProperty(WebApp webapp, String property)
{
try {
// read from file and put it into Map instance variable
// of calling class (UDEManager)
propertyMap.put(key, value);
} catch(Exception e) {
sysoutAndLog("Error while reading property ");
e.printStackTrace();
}
return false;
}
private void writeToPropertyFile()
{
try {
// Write data into remote file
} catch (Exception e) {
sysoutAndLog("exception while writing to file.");
e.printStackTrace();
}
}
}
You should associate the properties map with the user session or request
I have this class (my database connection factory):
#ApplicationScoped
public class ConnectionFactory {
private ComboPooledDataSource datasource;
private Long open = 0l;
private Long close = 0l;
#PostConstruct
public void init() throws PropertyVetoException, SQLException {
datasource = new ComboPooledDataSource();
datasource.setDriverClass("org.postgresql.Driver");
datasource.setJdbcUrl("jdbc:postgresql:dbcampanha");
datasource.setUser("postgres");
datasource.setPassword("admin");
datasource.setMinPoolSize(1);
datasource.setMaxPoolSize(5);
datasource.setCheckoutTimeout(30000);
datasource.setUnreturnedConnectionTimeout(30);
datasource.setMaxIdleTime(30);
datasource.setDebugUnreturnedConnectionStackTraces(true);
datasource.setAcquireIncrement(1);
}
#Produces
#RequestScoped
public Connection getConnection() throws ClassNotFoundException {
open++;
try {
Connection connection = datasource.getConnection();
connection.setAutoCommit(false);
return connection;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void close(#Disposes Connection connection) {
close++;
try {
connection.commit();
connection.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public Long getOpenedConnectionCounter() {
return open;
}
public Long getClosedConnectionCounter(){
return close;
}
public ComboPooledDataSource getDatasource(){
return datasource;
}
}
I use this class with an JAX-RS application. And for some tests using this route:
#RequestScoped
#Path("/test")
public class TesteService {
#Inject
private Connection connection;
#GET
#Produces(MyMediaType.JSON)
#Path("/yes")
public Response success() throws SQLException {
connection.getClientInfo("");
return Response.ok().build();
}
}
And this class for my Client:
public class TesteMain {
private static final String prefix = "http://localhost:8080/schoolwork/service/test/";
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10000; i++) {
Request request = new Request(prefix + "yes");
request.start();
if(i % 10 == 0)
Thread.sleep(1000l);
}
}
public static class Request extends Thread {
private String rota;
public Request(String rota){
this.rota = rota;
}
#Override
public void run() {
try {
HttpURLConnection url = (HttpURLConnection) (new URL(rota).openConnection());
url.connect();
System.out.println(url.getResponseCode() == 200 ? "SUCCESS" : "ERROR");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I receive this infos:
{
"opened-connection": 789,
"closed-connection": 867,
}
Yes, I have a number of closed database connection greater than opened. HOW? Any idea for this?
I use
Tomcat 7 + Java 7
P.S. I am sorry for my bad English :/
SOLVED
I change my counters for AtomicInteger objects, and works perfectly.
So, two quick comments:
Your counters are (boxed) longs read and updated willy-nilly by 1000 concurrent Threads. Their values will in general be unpredictable and nondeterministic. They certainly won't accurately count what you intend them to count. Consider using atomic operations on AtomicLongs instead.
Your commit() (or rollback()) should be attached to your database business logic, the part where you can tell a unit of work has either succeeded or failed. You shouldn't automatically commit on close.
I'm trying to build a simple mailer daemon for a Tomcat 7, MySQL app (and Eclipse). This the first time I have tried to use a ServletContextListener.
Everything works perfectly. Except, if I change my mailer code, and Tomcat reloads the class. It then bombs with a JNDI exception where it can't find the database. I'm not comfortable using it as-is. I don't want a class reload to kill the task on the server.
Everything works fine after a restart and before the reload. So I must be missing something or doing things in the wrong order.
The database connection is done in the DAO. So after restarting, the DAO must be getting severed?
Any help would be most appreciated...
The error I am getting is:
Name [comp/env/jdbc/somedb] is not bound in this Context. Unable to find [comp].
javax.naming.NameNotFoundException: Name [comp/env/jdbc/somedb] is not bound in this Context. Unable to find [comp].
PooledConnection has already been closed.
at org.apache.naming.NamingContext.lookup(NamingContext.java:819)
at org.apache.naming.NamingContext.lookup(NamingContext.java:167)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:156)
at javax.naming.InitialContext.lookup(Unknown Source)
at util.DbUtil.getConnection(DbUtil.java:23)
at dao.NoticeDao.getNoticesByEvent(NoticeDao.java:49)
at dao.NoticeDao.getNoticesByStatus(NoticeDao.java:46)
at util.AppMailer.sendMailQueue(AppMailer.java:88)
at util.AppMailer.run(AppMailer.java:71)
at java.lang.Thread.run(Unknown Source)
java.sql.SQLException: PooledConnection has already been closed.
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:86)
at com.sun.proxy.$Proxy7.prepareStatement(Unknown Source)
at dao.NoticeDao.getNoticesByEvent(NoticeDao.java:60)
at dao.NoticeDao.getNoticesByStatus(NoticeDao.java:46)
at util.AppMailer.sendMailQueue(AppMailer.java:88)
at util.AppMailer.run(AppMailer.java:71)
at java.lang.Thread.run(Unknown Source)
Update: For a second attempt, I simplified and separated the daemon stuff from the application logic. The app logic is now fully standalone. But I have the same problem.
public class AppMailerRunner implements ServletContextListener {
private ServletContext context = null;
private Thread mailerThread;
public AppMailerRunner() {}
#Override
public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();
System.out.printf("Starting: %s\n",this.getClass());
mailerThread = new Thread(new MailerDaemon());
mailerThread.setDaemon(true);
mailerThread.start();
}
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.printf("Stopping: %s\n",this.getClass());
mailerThread.interrupt();
this.context = null;
}
class MailerDaemon implements Runnable {
#Override
public void run() {
AppMailer appMailer = new AppMailer();
while(!Thread.currentThread().isInterrupted()){
try {
appMailer.sendMailQueue();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
...
<listener>
<listener-class>util.AppMailerRunner</listener-class>
</listener>
...
public class AppMailer{
private NoticeDao noticeDao;
private Session mailSession;
private Boolean sending;
...
public AppMailer() {
super();
noticeDao = new NoticeDao();
sending = false;
}
do stuff...
...
public class NoticeDao {
public NoticeDao() {
}
...
public List<Notice> getNotices() {
Connection conn = DbUtil.getConnection();
List<Notice> notices = new ArrayList<Notice>();
try {
PreparedStatement ps = conn.prepareStatement("SELECT * FROM notices");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Notice notice = mapFields(rs);
notices.add(notice);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
DbUtil.close(conn);
}
return notices;
}
private static Notice mapFields(ResultSet rs) throws SQLException {
Notice notice = new Notice();
notice.setId( rs.getLong("id"));
notice.setItemid( rs.getLong("itemid"));
notice.setItemtype( rs.getString("itemtype"));
notice.setTestmode( rs.getBoolean("testmode"));
notice.setName( rs.getString("name"));
notice.setStatus( rs.getString("status"));
notice.setError( rs.getString("error"));
notice.setCreated( rs.getDate("created"));
notice.setModified( rs.getDate("modified"));
notice.setLog( rs.getString("log"));
return notice;
}
...
}
...
public class DbUtil {
private static Connection conn = null;
public DbUtil() {
}
public static Connection getConnection() {
InitialContext ctx;
try {
ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/somedb");
conn = ds.getConnection();
} catch (NamingException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn){
if(conn!=null)
try {
conn.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
Try adding break statement in the catch block in your MailerDaemon class.
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
Note that interruption status is cleared when InterruptedException is thrown. So the thread created in the contextInitialized will never break out of the loop.
See the javadoc here.
Hope this helps.
I have my own connection pool class
public class ConnectionPool {
private static final Logger log = Logger.getLogger(ConnectionPool.class);
public final static String PROPERTIES_FILENAME = "config";
public static final int DEFAULT_POOL_SIZE = 10;
//single instance
private static ConnectionPool instatance;
//queue of free connections
private BlockingQueue<Connection> connectionQueue;
public ConnectionPool(String driver, String url, String user,
String password, int poolSize)
throws ClassNotFoundException, DAOException{
try{
Class.forName(driver);
connectionQueue = new ArrayBlockingQueue<Connection>(poolSize);
for(int i = 0; i < poolSize ;i++){
Connection connection = DriverManager.getConnection(url, user, password);
connectionQueue.offer(connection);
}
}
catch (SQLException e) {
log.error(e);
throw new DAOException(e.getMessage());
}
}
public static void init() throws DAOException{
try {
if(instatance == null){
String driver = ConfigurationManager.
getInstance().getProperty("DATABASE_DRIVER_NAME");
String url = ConfigurationManager.
getInstance().getProperty("DATABASE_URL");
String user = ConfigurationManager.
getInstance().getProperty("DATABASE_USER");
String password = ConfigurationManager.
getInstance().getProperty("DATABASE_PASSWORD");
String poolSizeStr = ConfigurationManager.
getInstance().getProperty("DATABASE_POOLSIZE");
int poolSize = (poolSizeStr != null) ?
Integer.parseInt(poolSizeStr) : DEFAULT_POOL_SIZE;
log.info("Trying to create pool of connections...");
instatance = new ConnectionPool(driver,url,user,password,poolSize);
log.info("Connection pool initialized");
}
}catch (ClassNotFoundException e) {
log.error(e);
} catch (SQLException e) {
log.error(e);
throw new DAOException(e.getMessage());
}
}
public static void dispose() throws DAOException {
try {
if(instatance != null){
instatance.clearConnectionQueue();
instatance = null;
log.info("Connection queue is disposed");
}
} catch (DAOException e) {
log.info(e.getMessage());
throw new DAOException(e.getMessage());
}
}
public static ConnectionPool getInstance(){
return instatance;
}
public Connection takeConnection() {
Connection connection = null;
try{
connection = connectionQueue.take();
}catch (InterruptedException e) {
log.info("Free connection waiting interrupted.Returned null connection");
log.error(e);
}
return connection;
}
public void releaseConnection(Connection connection) throws DAOException {
try {
if(!connection.isClosed()){
if(!connectionQueue.offer(connection)){
log.info("Connections is not added.");
}
}
else{
log.info("Trying to release closed connection.");
}
} catch (SQLException e) {
log.info("SQLException at connection isClosed(). Connection is not added");
throw new DAOException(e.getMessage());
}
}
private void clearConnectionQueue() throws DAOException{
try {
Connection connection;
while((connection = connectionQueue.poll()) != null){
if(!connection.getAutoCommit()){
connection.commit();
connection.close();
}
}
} catch (SQLException e) {
log.info(e.getMessage());
throw new DAOException(e.getMessage());
}
}
and need it to be initialized in the begining of struts servlet's life cycle. If it were regular servlet I'd used init() method not thinking, and I'd done it:
public class LinkAction extends DispatchAction {
private static final String PARAM_NAME_LANGUAGE = "language";
/**
* This is the Struts action method called on
* http://.../actionPath?method=myAction1,
* where "method" is the value specified in <action> element :
* ( <action parameter="method" .../> )
*/
private static ConnectionPool connectionPool =
ConnectionPool.getInstance();
public void init(){
try {
if(connectionPool == null){
ConnectionPool.init();
connectionPool = ConnectionPool.getInstance();
}
} catch (DAOException e) {
log.error(e);
}
}
public ActionForward newsList(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return mapping.findForward("newsList");
}
public ActionForward addNews(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
return mapping.findForward("addNews");
}
public ActionForward changeLocale(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String localeValue = request.getParameter("localeValue");
request.getSession().setAttribute(PARAM_NAME_LANGUAGE, localeValue);
return mapping.findForward("newsList");
}
}
But this doesn't work with Struts Action, so I decided that it could be done in the struts-config.xml or web.xml. But how?
I think that you should use a ServletContextListener:
http://docs.oracle.com/javaee/6/api/javax/servlet/ServletContextListener.html
Even when using another framework it's a great place to put data source initialization code.
This listener is called every time your applications comes up and running so that you can put your datasource into a context attribute and recover it whenever necessary.
I'm trying create very simple Comet Servlet which will push Hello World message to subscribers:
#WebServlet("/ChatServlet")
public class ChatServlet extends HttpServlet implements CometProcessor {
private static final long serialVersionUID = 1L;
private MessageSender messageSender = null;
private static final Integer TIMEOUT = 60 * 1000;
public void init(ServletConfig config) throws ServletException {
messageSender = new MessageSender();
Thread messageSenderThread =
new Thread(messageSender);
messageSenderThread.setDaemon(true);
messageSenderThread.start();
}
public void destroy() {
// messageSender.stop();
messageSender = null;
}
#Override
public void event(CometEvent event) throws IOException, ServletException {
HttpServletRequest request = event.getHttpServletRequest();
HttpServletResponse response = event.getHttpServletResponse();
if (event.getEventType() == CometEvent.EventType.BEGIN) {
request.setAttribute("org.apache.tomcat.comet.timeout", TIMEOUT);
System.out.println("Begin for session: " + request.getSession(true).getId());
messageSender.setConnection(response);
}
else if (event.getEventType() == CometEvent.EventType.ERROR) {
System.out.println("Error for session: " + request.getSession(true).getId());
event.close();
} else if (event.getEventType() == CometEvent.EventType.END) {
System.out.println("End for session: " + request.getSession(true).getId());
event.close();
} else if (event.getEventType() == CometEvent.EventType.READ) {
throw new UnsupportedOperationException("This servlet does not accept data");
}
}
}
and then my Runnable looks like this:
public class MessageSender implements Runnable {
protected boolean running = true;
protected final List<String> messages = new ArrayList<String>();
private ServletResponse connection;
public synchronized void setConnection(ServletResponse connection){
this.connection = connection;
notify();
}
#Override
public void run() {
while (running) {
if (messages.size() == 0) {
try {
synchronized (messages) {
messages.wait();
}
} catch (InterruptedException e) {
// Ignore
}
}
String[] pendingMessages = null;
synchronized (messages) {
pendingMessages = messages.toArray(new String[0]);
messages.clear();
}
try {
if (connection == null){
try{
synchronized(this){
wait();
}
} catch (InterruptedException e){
// Ignore
}
}
PrintWriter writer = connection.getWriter();
writer.println("hello World");
System.out.println("Writing Hello World");
writer.flush();
writer.close();
connection = null;
System.out.println("Closing connection");
} catch (IOException e) {
System.out.println("IOExeption sending message"+e.getMessage());
}
}
}
}
now my Dojo cometd code looks like this:
<script src="dojo/dojo.js"></script>
<script type="text/javascript">
dojo.require("dojox.cometd");
dojo.addOnLoad(function(){
dojox.cometd.init("ChatServlet");
dojox.cometd.subscribe("ChatServlet", window, "alertMessage");
});
function alertMessage(message) {
alert("Message: " + message);
}
</script>
Now when I load client I'm getting the following error:
Begin for session: C898A372F1B1199C04CA308F715ABC36Nov 6, 2011 2:00:48 PM org.apache.catalina.core.StandardWrapperValve event
SEVERE: Servlet.service() for servlet [com.vanilla.servlet.ChatServlet] in context with path [/Servlet3Comet] threw exception
java.lang.UnsupportedOperationException: This servlet does not accept data
at com.vanilla.servlet.ChatServlet.event(ChatServlet.java:75)
Error for session: C898A372F1B1199C04CA308F715ABC36
End for session: C898A372F1B1199C04CA308F715ABC36
What am I doing wrong?
Why does cometD subscription invokes CometEvent.EventType.READ?
Does anybody have any working comet example?
P.S: I did switch to Nio according to Tomcat configuration.
Documentation for init(ServletConfig):
public void init(ServletConfig config) throws ServletException Called
by the servlet container to indicate to a servlet that the servlet is
being placed into service.
See Servlet#init. This implementation stores the ServletConfig object
it receives from the servlet container for later use. When overriding
this form of the method, call super.init(config).
And Documentation for init():
public void init() throws ServletException A convenience method which
can be overridden so that there's no need to call super.init(config).
Instead of overriding init(ServletConfig), simply override this method
and it will be called by GenericServlet.init(ServletConfig config).
The ServletConfig object can still be retrieved via
getServletConfig().
When overriding init(ServletConfig), your first call must be super.init(config);