package examples.jms.webshare;

import java.io.*;
import javax.naming.*;
import javax.jms.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

/** 
 * This example is a servlet that allows users to rate web pages and
 * receive other users' web page ratings. It demonstrates these
 * features of JMS:
 *
 * <p>
 * <ul>
 * <li>Publish/subscribe (Topic) messaging model.
 * <li>Using a MapMessage. 
 * <li>Setting and checking the JMSType header field.
 * <li>Setting message properties.
 * <li>Using durable subscriptions.
 * <li>Using message selectors to filter messages. 
 * </ul>
 *
 * <p> 
 * Any user can publish a web page rating.  The servlet requires
 * users to log in with a ClientID. This ClientID is used to 
 * reconnect a TopicSubscriber so that the user can
 * receive all of the messages posted. The ClientID is also
 * used in messages to identify the user who published the
 * web page rating.  
 *
 *<p>
 * Configure the server:
 * <ol>
 * <li>
 * Set <tt>weblogic.httpd.session.enable=true</tt> in the
 * <tt>weblogic.properties</tt> file. 
 * <li>
 * You must have a connection
 * pool configured and assigned to JMS in the
 * <tt>weblogic.properties</tt> file. See <a href="../index.html">JMS Examples</a> 
 * for instruction on how to set up a connection pool for JMS.
 * <li>
 * Set up a JMS Topic and a Durable ClientID by adding these properties to
 * your <tt>weblogic.properties</tt> file:
 * <pre>
 *   weblogic.jms.topic.webshareTopic=jms.topic.webshareTopic
 *   weblogic.jms.connectionFactoryName.webshare=jms.connection.webshareFactory
 *   weblogic.jms.connectionFactoryArgs.webshare=ClientID=webshareUser</pre>
 * <li>
 * Register the servlet in your <tt>weblogic.properties</tt> file
 * by adding this property:
 * <pre>  weblogic.httpd.register.webshare=examples.jms.webshare.WebshareServlet</pre>
 * <li>
 * Set the servlet classpath and reload properties in your <tt>weblogic.properties</tt> file
 * by adding the following properties:
 *<pre>  weblogic.httpd.servlet.classpath=<i>weblogic</i>/myserver/servletclasses
 *  weblogic.httpd.servlet.reloadCheckSecs=1</pre>
 * where <tt><i>weblogic</i></tt> is the directory where WebLogic is installed.
 * </ol>
 * Build the example:
 * <ol>
 * <li>
 * Set up your development shell, as described in 
 * <a href="../../techstart/environment.html">Setting up 
 * your environment</a>.
 * <li>
 * Compile the files in this directory as shown in this examples for Windows NT:
 * <pre>  $<font face="Courier New"><b> javac -d %SERVLET_CLASSES% WebshareServlet.java</b></font></pre>
 * </ol>
 * Run the example:
 * <ol>
 * <li>
 * Start the WebLogic Server in a new command shell.
 *  <li>
 * Load the servlet in a browser with a URL like this:
 * <pre>  http://<i>hostname</i>:<i>port</i>/webshare</pre>
 * where:
 * <dl>
 * <dt><i><font face="Courier New" size=-1>hostname</font></i>
 * <dd>Host name of the WebLogic Server
 * <dt><i><font face="Courier New" size=-1>port</font></i>
 * <dd>Port where the WebLogic Server is listening for connections
 * (<font face="Courier New" size=-1>weblogic.system.ListenPort</font>). 
 * </dl>
 *<li>
 * Log in to establish a session with the servlet. Then you
 * can choose to rate web pages, view the posted web page listings, or
 * change your subscription information. 
 * </ol>
 *
 * @author Copyright (c) 1999-2000 by BEA Systems, Inc. All Rights Reserved.  
 */
public class WebshareServlet extends HttpServlet
  implements SingleThreadModel
{
  public final static String JMS_FACTORY="jms.connection.webshareFactory";
  public final static String TOPIC="jms.topic.webshareTopic";
  public final static String MESSAGE_TYPE="webshare1.0";

  public void service(HttpServletRequest req, HttpServletResponse res)
       throws IOException, ServletException
  {
    String userName = null;
    String category;
    int rating;
    String url;
    String pagetitle;
    String summary;
    String posters;
    int minRating;
    String categoryList;

    HttpSession session;

    // Get the session object to store the log in name. 
    session = req.getSession(true);
    
    try {
      // See if client is already logged in
      if (session.isNew() 
          || ! req.getMethod().equals("POST")) { // not logged in yet
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          getLogin(pw);           // Send the login page
          return;                 // POST method handles login
        } 
         
      if (req.getMethod().equals("GET")) {
          userName = (String) session.getAttribute("user");
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          printForm(pw, userName);
      }


      // Process input from forms
      if (req.getMethod().equals("POST")) {
          
        // Completed login 
        if (req.getParameterValues("login") != null) {
          userName = req.getParameterValues("user")[0].trim();
          if (userName.length() < 1) {
              PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
              getLogin(pw);           // Send the login page
              return;                 // POST method handles login
          }
          session.setAttribute("user", userName);
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          pw.println("<html><title>Logged in</title><body bgcolor=#FFFFFF>");
          pw.print("WebShare 1.0<br>User: ");
          pw.println(userName);
          pw.println("<hr>");
          pw.print("Logged in user ");
          pw.print(userName);
          pw.println(".");
          getOptions(pw);     // Standard choice buttons
          pw.println("</body></html>");
          pw.close();
          return;
        } 
          
        // Wants to rate a site
        if (req.getParameterValues("dorate") != null) {
          userName = (String) session.getAttribute("user");
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          printForm(pw, userName); // Send the rating page
          return;
        }
          
        // Wants to retrieve others' ratings
        if (req.getParameterValues("getratings") != null) {
          userName = (String) session.getAttribute("user");
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          getRatings(pw, userName);
          return;
        }
          
        // Wants to manage subscription
        if (req.getParameterValues("subscription") != null) {
          userName = (String) session.getAttribute("user");
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          editSubscription(pw, userName);
          return;
        }

        // Update subscription (selector) with new values
        if (req.getParameterValues("updateSub") != null) {
          userName = (String) session.getAttribute("user");
          posters = req.getParameterValues("posters")[0];
          minRating = 1;
          if (req.getParameterValues("rating") != null) 
            minRating = Integer.parseInt(req.getParameterValues("rating")[0]);
          categoryList = "";
          if (req.getParameterValues("category") != null) {
            for (int i = 0;
                 i < req.getParameterValues("category").length; i++) {
              categoryList += "'" + req.getParameterValues("category")[i]
                + "',";
            }
            categoryList = categoryList.substring(0,categoryList.length()-1);
          }
          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          installSelector(pw, userName, posters, minRating, categoryList);
          return;
        }
         
          
        // Delete the durable subscripter
        if (req.getParameterValues("dropSub") != null) {
          userName = (String) session.getAttribute("user");

          PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
          deleteSubscription(pw, userName);
          return;
        }

        // Finished rating a site
        if (req.getParameterValues("rate") != null) {
          userName = (String) session.getAttribute("user");
          category = req.getParameterValues("category")[0];
          if (req.getParameterValues("rating")[0] != null)
              rating = Integer.parseInt(req.getParameterValues("rating")[0]);
          else
              rating = 1;
          summary = req.getParameterValues("summary")[0];
          pagetitle = req.getParameterValues("pagetitle")[0];
          url = req.getParameterValues("url")[0];
            
          shareUrl(userName, category, rating, summary, pagetitle, url);
            
          res.setContentType("text/html");
          res.setHeader("Pragma", "no-cache");
          PrintWriter pw = new PrintWriter(res.getOutputStream(),true);
          pw.println("<html><head><title>Recommendation submitted</title></HEAD>");
          pw.println("<body><h1><font color=#FF0000>Recommendation submitted</font></h1>");
          pw.println("<hr><p>");
          pw.println("<table bgcolor=#FCF3E2 border=0 cellpadding=2 cellspacing=3>");
          pw.println("<tr><th>Web page</th>");
          pw.print("<td><a href=\"");
          pw.print(url);
          pw.println("\">");
          pw.println(pagetitle);
          pw.println("</a></td></tr>");
          pw.print("<tr><th>Rated by</th><td>");
          pw.print(userName);
          pw.println("</td></tr><tr><th>Category</th><td>");
          pw.println(category);
          pw.println("</td></tr><tr><th>Rating</th><td>");
          for (int i = 0; i < rating; i++) {
            pw.print("* ");
          }
          pw.println("</td></tr>");
          pw.println("<tr><th>Reviewer's summary</th><td><p>");
          pw.println(summary);
          pw.println("</td></tr></table><p>");
          getOptions(pw);
          pw.println("</body></html>");
          pw.close();
          return;
        }

        // if we're here, user probably pressed return on the login screen
        // anyway, this will be the default action
        userName = req.getParameterValues("user")[0].trim();
        PrintWriter pw = new PrintWriter(res.getOutputStream(), true);
        getLogin(pw);           // Send the login page
        return;                 // POST method handles login
      }
    }
    catch (Exception e) {e.printStackTrace(); }
  }

  /**
   * Draws the login HTML page. 
   */
  public void getLogin(PrintWriter pw)
       throws Exception
  {
    pw.println("<html><head><title>WebShare Login</title></head>");
    pw.println("<body bgcolor=#FFFFFF><Font face=Helvetica>");
    pw.println("WebShare 1.0<hr>");
    pw.println("<h1><font color=#FF0000>Log into WebShare</font></h1>");
    pw.println("<form method=\"post\" action=\"webshare\">");
    pw.println("<table align=Center bgcolor=#FCF3E2 cellspacing=3 border=0 cellpadding=2>");
    pw.println("<tr><th>Login name</th>");
    pw.println("<td><input name=user size=40></td></tr>");
    pw.println("<td colspan=2 align=center>");
    pw.println("<input type=\"submit\" name=\"login\" value=\"Log in\"></td></tr>");
    pw.println("</table></form></body></html>");
    pw.close();
  }

  /** 
   * Sticks standard buttons on the bottom of pages. Pressing one
   * of these buttons determines which post method the service() method
   * is going to process. 
   */
  public void getOptions(PrintWriter pw)
       throws Exception
  {
    pw.println("<hr>");
    pw.println("<form method=\"post\" action=\"webshare\">");
    pw.println("<table align=center cellspacing=3 border=0 cellpadding=2>");
    pw.println("<td colspan=2 align=center width=100%>");
    pw.println("<input type=\"submit\" name=\"dorate\" value=\"Rate a Site\">  ");
    pw.println("<input type=\"submit\" name=\"getratings\" value=\"Get Ratings\">");
    pw.println("<input type=submit name=subscription value=\"Manage Subscription\">");
    pw.println("</td></tr>");
    pw.println("</table></form></center>");
  }

    
  /**
   * Displays the website review form.  
   */
  public void printForm(PrintWriter pw, String login) 
       throws Exception
  {
    pw.println("<html><head><title>WebShare</title></head>");
    pw.println("<body bgcolor=#FFFFFF><font face=Helvetica>");
    pw.print("WebShare 1.0<br>User: ");
    pw.println(login);
    pw.println("<h1><h1><font color=#FF0000>Recommend a Web Page</font></h1>");
    pw.println("<form method=\"post\" action=\"webshare\">");
    pw.println("<table align=center bgcolor=#FCF3E2 cellspacing=3 border=0 cellpadding=2>");
    pw.println("<tr><th>Category</th>");
    pw.println("<td><select name=category>");
    pw.println("<option value=general selected>General interest");
    pw.println("<option value=company>Company news");
    pw.println("<option value=competition>Competitive news");
    pw.println("<option value=national>National news");
    pw.println("<option value=local>Local news");
    pw.println("<option value=humor>Humor");
    pw.println("</select></td></tr>");
    pw.println("<tr><th>Rating</th>");
    pw.println("<td><input type=radio name=rating value=1>*<br>");
    pw.println("<input type=radio name=rating value=2>* *<br>");
    pw.println("<input type=radio name=rating value=3 checked>* * *<br>");
    pw.println("<input type=radio name=rating value=4>* * * *<br>");
    pw.println("<input type=radio name=rating value=5>* * * * *");
    pw.println("</td></tr>");
    pw.println("<tr><th>Title</th>");
    pw.println("<td><input name=\"pagetitle\" size=60></td></tr>");
    pw.println("<tr><th>URL</th>");
    pw.println("<td><input name=\"url\" size=60></td></tr>");
    pw.println("<tr><th>Summary</th>");
    pw.println("<td><textarea name=\"summary\" rows=5 cols=60 wrap=true></textarea></td></tr>");
    pw.println("<tr><td colspan=2 align=center>");
    pw.println("<input type=\"submit\" name=\"rate\" value=\"Send rating\">");
    pw.println("<input type=\"reset\" value=\"Reset\"></td></tr>");
    pw.println("</table>");
    pw.println("</form>");
    pw.println("</font></body></html>");
    pw.close();
  }

  /**
   * Publishes a website review to the webshareTopic Topic. 
   */
  public void shareUrl(String user, String category, int rating, 
                       String summary, String pagetitle, String url)
       throws NamingException, JMSException
  {
    Context ctx = new InitialContext();
    TopicConnectionFactory tconFactory;
    TopicConnection connection;
    TopicSession session;
    TopicPublisher publisher;
    Topic topic;
    MapMessage msg;

    tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
    connection = tconFactory.createTopicConnection();
    session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    try {
      topic = (Topic) ctx.lookup(TOPIC);
    } catch (NamingException ne) {
      topic = session.createTopic(TOPIC);
      ctx.bind(TOPIC, topic);
    }
    publisher = session.createPublisher(topic);
    msg = session.createMapMessage();
    // Set the type of message so receivers know what to do with it
    msg.setJMSType(MESSAGE_TYPE);
    
    // Properties used for selectors
    msg.setStringProperty("User", user);
    msg.setStringProperty("Category", category);
    msg.setIntProperty("Rating", rating);

    // Message body
    msg.setString("User", user);
    msg.setString("Category", category);
    msg.setString("Summary", summary);
    msg.setInt("Rating", rating);
    msg.setString("PageTitle", pagetitle);
    msg.setString("Url", url);

    publisher.publish(msg, DeliveryMode.PERSISTENT, 10, 0);

    publisher.close();
    session.close();
    connection.close();
  }
  
    /**
     * Delete the user's durable subscriber.
     *
     */
    public void deleteSubscription(PrintWriter pw, String userName)
    throws NamingException, JMSException, Exception
    {
        Context ctx = new InitialContext();
        TopicConnectionFactory tconFactory;
        TopicConnection connection;
        TopicSession session;
        TopicSubscriber subscriber;
        Topic topic;

        tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
        topic = (Topic) ctx.lookup(TOPIC);
        connection = tconFactory.createTopicConnection();
        
        // Override configured ClientID with the login ID
        connection.setClientID(userName); 
        session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
        
        pw.println("<html><head><title>Delete Subscription</title></head>");
        pw.println("<body bgcolor=#FFFFFF><h1><font face=Helvetica color=#FF0000>");
        pw.println("Delete Subscription</font></h1>");
        pw.println("<hr><p>");

        try {
            session.unsubscribe(userName);
            pw.println("Deleted subscription for " + userName);
        }
        catch (JMSException je) {
            pw.println("No subscription to delete for " + userName);
        }

        pw.println("<p>");
        getOptions(pw);
        pw.println("</body></html>");
        pw.close();
        
        session.close();
        connection.close();
    }


  /**
   * Create a DurableSubscription and MessageSelector for the
   * current logged in user. 
   */
  public void editSubscription(PrintWriter pw, String user)
       throws NamingException, JMSException, Exception
  {
    String posters = null;

    pw.println("<html><head><title>Edit Subscription</title></head>");
    pw.println("<body bgcolor=#FFFFFF><h1><font face=Helvetica color=#FF0000>");
    pw.println("Edit WebShare Subscription</font></h1>");
    pw.print("<b>User: </b>");
    pw.println(user);
    pw.println("<hr>");
    pw.println("<form method=\"post\" action=\"webshare\">");
    pw.println("<table align=center cellspacing=3 border=0 cellpadding=2 bgcolor=#fcf3e2>");
    pw.println("<tr><th>Receive ratings posted by</th>");
    pw.println("<td><input name=posters size=60><br>");
    pw.println("<font size=-1><i>(Enter a comma-separated list of posters)</i></td></tr>");
    pw.println("<tr><th>Receive ratings about</th><td>");
    pw.println("<input type=checkbox name=category value=general>General interest<br>");
    pw.println("<input type=checkbox name=category value=company>Company news<br>");
    pw.println("<input type=checkbox name=category value=competition>Competitive news<br>");
    pw.println("<input type=checkbox name=category value=national>National news<br>");
    pw.println("<input type=checkbox name=category value=local>Local news<br>");
    pw.println("<input type=checkbox name=category value=humor>Humor<br>");
    pw.println("</td></tr>");
    pw.println("<tr><th>Minimum rating</th><td>");
    pw.println("<input type=radio name=rating value=1>*<br>");
    pw.println("<input type=radio name=rating value=2>* *<br>");
    pw.println("<input type=radio name=rating value=3>* * *<br>");
    pw.println("<input type=radio name=rating value=4>* * * *<br>");
    pw.println("<input type=radio name=rating value=5>* * * * *</td></tr>");
    pw.println("<td colspan=2 align=center>");
    pw.println("<input type=submit name=updateSub value=\"Update Subscription\">");
    pw.println("<input type=submit name=dropSub value=\"Delete Subscription\">");
    pw.println("</td></tr></table></u></form></body></html>");
  }

  /** 
   * Create a selector string and update the user's DurableSubscription
   *
   */
  public void installSelector(PrintWriter pw, String userName, String posters, 
                              int minRating, String categoryList)
       throws NamingException, JMSException, Exception
  {
    Context ctx = new InitialContext();
    TopicConnectionFactory tconFactory;
    TopicConnection connection;
    TopicSession session;
    TopicSubscriber subscriber;
    Topic topic;
    String selector;

    selector = " ";
    if (posters.length() > 0) {
      selector = "User IN ('"; 
      StringTokenizer st = new StringTokenizer(posters, ", ");
      while (st.hasMoreTokens()) {
        selector = selector + st.nextToken() + "','";
      }
      selector = selector.substring(0, selector.length() - 2) + ")";
    }

    if (categoryList.length() > 0) {
      if (selector.length() > 1) 
        selector += " AND ";
      selector += "Category IN (" + categoryList + ")";
    }
    if (minRating > 1) {
      // don't bother if it's 1
      if (selector.length() > 1)
         selector += " AND ";
      selector += "Rating > " + minRating;
    }
    if (selector.length() == 1) {
      selector = "TRUE";        // default is select all
    }
    // alter durable subscription is not yet implemented. 
    // Create a DurableSubscriber with the new selector
    tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
    topic = (Topic) ctx.lookup(TOPIC);
    connection = tconFactory.createTopicConnection();

     // Override configured ClientID with the login ID
    connection.setClientID(userName); 
    session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

    // Create the subscription
    subscriber = session.createDurableSubscriber(topic, userName, selector, false);
      
    session.close();
    connection.close();
    

    pw.println("<html><head><title>Updated Subscription</title></head>");
    pw.println("<body><H1><font face=Helvetica color=#FF0000>");
    pw.println("Updated Subscription</font></h1><hr>");
    pw.println("New selector for ");
    pw.println(userName);
    pw.println(" is:<p>");
    pw.println(selector);
    pw.println("<p>");
    getOptions(pw);
    pw.println("</body></html>");
    pw.close();
  }



  /**
   * Reads website recommendations from the webshareTopic JMS Topic.
   * Creates a DurableSubscriber for whomever is logged in. 
   */
  public void getRatings(PrintWriter pw, String user)
       throws NamingException, JMSException, Exception
  {
    Context ctx = new InitialContext();
    TopicConnectionFactory tconFactory;
    TopicConnection connection;
    TopicSession session;
    TopicSubscriber subscriber;
    Topic topic;
    MapMessage msg;

    tconFactory = (TopicConnectionFactory) ctx.lookup(JMS_FACTORY);
    topic = (Topic) ctx.lookup(TOPIC);
    connection = tconFactory.createTopicConnection();

    // Override configured ClientID with the login ID
    connection.setClientID(user); 
    session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
    // Create the subscription
    subscriber = session.createDurableSubscriber(topic, user);
    connection.start();

    pw.println("<html><head><title>WebShare Ratings</title></head>");
    pw.println("<body><h1><font face=\"Helvetica\" color=#FF0000>");
    pw.print("WebShare 1.0<br>User: ");
    pw.println(user);
    pw.println("</h1><hr>");
    pw.println("<table align=center bgcolor=#FCF3E2 border=0 cellspacing=3 cellpadding=2>");
    for (int nMessages=0;
         (nMessages < 5) && (msg = (MapMessage) subscriber.receive(3*1000)) != null;
         nMessages++)
      {
        // Make sure it's our kind of message. 
        if (msg.getJMSType().equals(MESSAGE_TYPE)) {
          pw.println("<tr><th>Web page</th>");
          pw.print("<td><a href=\"");
          pw.print(msg.getString("Url"));
          pw.print("\">");
          pw.print(msg.getString("PageTitle"));
          pw.println("</a></td></tr>");
          pw.println("<tr><th>Rated by</th><td>");
          pw.print(msg.getString("User"));
          pw.println("</td></tr>");
          pw.println("<tr><th>Category</th><td>");
          pw.println(msg.getString("Category"));
          pw.println("</td></tr>");
          pw.println("<tr><th>Rating</th><td>");
          for (int i = 0; i < msg.getInt("Rating"); i++) {
            pw.print("* ");
          }
          pw.println("</td></tr>");
          pw.println("<tr><th>Reviewer's Summary</th><td>");
          pw.println(msg.getString("Summary"));
          pw.println("</td></tr>");
        }
        else {                  // not our MESSAGE_TYPE
          pw.println("<tr><td colspan=2 align=center>");
          pw.println("Don't understand this message. Skipping.</td></tr>");
        }
        pw.println("<tr><td colspan=2><hr></td></tr>");
      }
    pw.println("</table>");    
    getOptions(pw);             // Standard options
    pw.println("</body></html>");
    subscriber.close();
    session.close();
    connection.close();
    pw.close();
  }


}



