KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > app > bugdb > BugSession


1 package com.quadcap.app.bugdb;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.ByteArrayInputStream JavaDoc;
42 import java.io.ByteArrayOutputStream JavaDoc;
43 import java.io.InputStream JavaDoc;
44 import java.io.PrintWriter JavaDoc;
45
46 import java.util.Enumeration JavaDoc;
47 import java.util.Hashtable JavaDoc;
48 import java.util.Properties JavaDoc;
49 import java.util.Vector JavaDoc;
50
51
52 import java.sql.DriverManager JavaDoc;
53 import java.sql.SQLException JavaDoc;
54
55 import java.net.URLDecoder JavaDoc;
56
57 import java.sql.Connection JavaDoc;
58 import java.sql.PreparedStatement JavaDoc;
59 import java.sql.ResultSet JavaDoc;
60 import java.sql.ResultSetMetaData JavaDoc;
61 import java.sql.Statement JavaDoc;
62 import java.sql.SQLException JavaDoc;
63
64 import javax.servlet.ServletException JavaDoc;
65 import javax.servlet.http.HttpServletRequest JavaDoc;
66 import javax.servlet.http.HttpSession JavaDoc;
67 import javax.servlet.http.HttpSessionBindingEvent JavaDoc;
68 import javax.servlet.http.HttpSessionBindingListener JavaDoc;
69 import javax.servlet.http.HttpSessionContext JavaDoc;
70
71 /**
72  * A session bean encapsulating access to the Quadcap Bug Database.
73  * JSP pages use methods of this bean to perform the various functions
74  * of the bug database application.
75  *
76  * @author Stan Bailes
77  */

78 public class BugSession implements HttpSessionBindingListener JavaDoc {
79     Connection JavaDoc conn;
80
81     /** My user name. 'nobody' until logged in. */
82     String JavaDoc me = "nobody";
83
84     String JavaDoc my_person_type = null;
85     boolean isAdmin = false;
86     boolean isManager = false;
87     boolean isDeveloper = false;
88     boolean isUser = false;
89
90     static Object JavaDoc lock = new Object JavaDoc();
91
92     Vector JavaDoc debug_history = new Vector JavaDoc();
93
94     PreparedStatement JavaDoc getComponentOwner;
95     PreparedStatement JavaDoc insertBugHist;
96     PreparedStatement JavaDoc insertPerson;
97     PreparedStatement JavaDoc getBugHist;
98     PreparedStatement JavaDoc getBug;
99     PreparedStatement JavaDoc getQuery;
100     PreparedStatement JavaDoc saveQuery;
101     PreparedStatement JavaDoc getUser;
102     PreparedStatement JavaDoc updateUser;
103     PreparedStatement JavaDoc deleteUser;
104     PreparedStatement JavaDoc getProject;
105     PreparedStatement JavaDoc newProject;
106     PreparedStatement JavaDoc deleteProject;
107     PreparedStatement JavaDoc updateProject;
108
109     final String JavaDoc driverName = "com.quadcap.jdbc.JdbcDriver";
110     final String JavaDoc dbUrl = "jdbc:qed:bugdb;create=true";
111     final String JavaDoc dbUser = "bugdb";
112     final String JavaDoc dbPass = "bugdb";
113
114     /**
115      * Create a new session.
116      */

117     public BugSession() {
118     // Make sure we're connected to the database. If we're absolutely
119
// the first user, load the schema.
120
try {
121         Class.forName(driverName);
122         getConnection();
123         prepareStatements();
124         checkSchema();
125     } catch (Exception JavaDoc e) {
126         e.printStackTrace(System.out);
127         throw new RuntimeException JavaDoc(e.toString());
128     }
129     }
130
131     /**
132      * Return the JDBC connection for this session.
133      *
134      * @return this session's connection.
135      */

136     public Connection JavaDoc getConnection() throws SQLException JavaDoc {
137     if (conn == null) {
138         Properties JavaDoc props = new Properties JavaDoc();
139         props.put("user", dbUser);
140         props.put("password", dbPass);
141         props.put("create", "true");
142         this.conn = DriverManager.getConnection(dbUrl, props);
143             //conn.setAutoCommit(false);
144
}
145     return conn;
146     }
147
148     /**
149      * This application object has just been bound into an HttpSession
150      *
151      * @param event identifies the session and the name in the
152      * session of this object.
153      */

154     public void valueBound (HttpSessionBindingEvent JavaDoc event) {
155     HttpSession JavaDoc session = event.getSession();
156     session.setMaxInactiveInterval(6 * 3600); // six hours
157
}
158     
159     /**
160      * This application object has just been removed from an HttpSession
161      *
162      * @param event identifies the session and the name in the
163      * session of this object.
164      */

165     public void valueUnbound (HttpSessionBindingEvent JavaDoc event) {
166     logout(null);
167     try {
168         conn.close();
169     } catch (Exception JavaDoc e) {}
170     }
171     
172
173     /**
174      * Prepare the various SQL statements we'll be using.
175      *
176      * @exception SQLException may be thrown
177      */

178     private final void prepareStatements() throws SQLException JavaDoc {
179     getComponentOwner = conn.prepareStatement(
180         "select owner from component where component = ?");
181
182     insertBugHist = conn.prepareStatement(
183         "insert into bug_history (bug_id, hist_pos, submitter," +
184         " abstract, description, comments, state, priority, type," +
185         " owner, component, modtime) values(?,?,?,?,?,?,?,?,?,?,?,?)");
186
187     insertPerson = conn.prepareStatement(
188         "insert into person(name,password,email,person_type) " +
189         "values(?,?,?,?,?)");
190
191     getBugHist = conn.prepareStatement("select hist_size from bug where" +
192                        " bug_id = ? for update",
193                        ResultSet.TYPE_SCROLL_SENSITIVE,
194                        ResultSet.CONCUR_UPDATABLE);
195     getBug = conn.prepareStatement("select * from bug_history " +
196                        "where bug_id = ? " +
197                        "order by hist_pos desc");
198     getQuery = conn.prepareStatement("select query from queries " +
199                      "where owner = ? and name = ?");
200     saveQuery = conn.prepareStatement("insert into queries values(?,?,?)");
201     getUser = conn.prepareStatement("select * from person where name=?");
202     updateUser = conn.prepareStatement(
203         "select * from person where name=? for update",
204         ResultSet.TYPE_SCROLL_SENSITIVE,
205         ResultSet.CONCUR_UPDATABLE);
206     deleteUser = conn.prepareStatement("delete from person where name=?");
207     getProject = conn.prepareStatement(
208         "select * from component where component=?");
209     newProject = conn.prepareStatement(
210         "insert into component values(?,?)");
211     updateProject = conn.prepareStatement(
212         "select * from component where component=? for update",
213         ResultSet.TYPE_SCROLL_SENSITIVE,
214         ResultSet.CONCUR_UPDATABLE);
215     deleteProject = conn.prepareStatement(
216         "delete from component where component=?");
217     }
218
219     /**
220      * Check to make sure the database schema exists. If not, load it
221      * from the <code>bugdb.sql</code> file.
222      *
223      * @exception SQLException may be thrown.
224      */

225     private final void checkSchema() throws SQLException JavaDoc {
226     synchronized (lock) {
227         Statement JavaDoc s = conn.createStatement();
228         ResultSet JavaDoc rs = null;
229         try {
230         rs = s.executeQuery("select * from singleton");
231         } catch (SQLException JavaDoc e) {
232         Loader loader = new Loader();
233         loader.setConnection(conn);
234                 ClassLoader JavaDoc c = this.getClass().getClassLoader();
235                 InputStream JavaDoc is = c.getResourceAsStream(
236                     "com/quadcap/app/bugdb/bugdb.sql");
237         loader.loadStream(is);
238         } finally {
239         if (rs != null) rs.close();
240         s.close();
241         }
242     }
243     }
244
245     /**
246      * Is this session associated with a valid user?
247      *
248      * @return true if the user is valid.
249      */

250     public boolean isUser() { return isUser; }
251
252     /**
253      * Is this session associated with a user with 'developer' privileges?
254      *
255      * @return true if the user is valid and has developer privileges.
256      */

257     public boolean isDeveloper() { return isDeveloper; }
258
259     /**
260      * Is this session associated with a user with 'manager' privileges?
261      *
262      * @return true if the user is valid and has manager privileges.
263      */

264     public boolean isManager() { return isManager; }
265
266     /**
267      * Is this session associated with a user with 'administrator' privileges?
268      *
269      * @return true if the user is valid and has administrator privileges.
270      */

271     public boolean isAdmin() { return isAdmin; }
272
273
274     /**
275      * Return the saved bug search query with the specified name
276      *
277      * @param name the name of the query
278      * @return the query string
279      * @exception ServletException may be thrown
280      */

281     public String JavaDoc getQuery(String JavaDoc name) throws ServletException JavaDoc {
282     try {
283         getQuery.clearParameters();
284         getQuery.setString(1, me);
285         getQuery.setString(2, name);
286         ResultSet JavaDoc rs = getQuery.executeQuery();
287         try {
288         if (rs.next()) {
289             return rs.getString(1);
290         } else {
291             return "";
292         }
293         } finally {
294         rs.close();
295         }
296     } catch (SQLException JavaDoc ex) {
297         throw new ServletException JavaDoc(ex.toString());
298     }
299     }
300
301     /**
302      * Save a bug search query.
303      *
304      * @param name the query name
305      * @param query the query string
306      * @exception ServletException may be thrown
307      */

308     public void saveQuery(String JavaDoc name, String JavaDoc query) throws ServletException JavaDoc {
309     try {
310         saveQuery.clearParameters();
311         saveQuery.setString(1, name);
312         saveQuery.setString(2, query);
313         saveQuery.setString(3, me);
314         saveQuery.executeUpdate();
315     } catch (SQLException JavaDoc ex) {
316         throw new ServletException JavaDoc(ex.toString());
317     }
318     }
319
320     /**
321      * Execute the 'logout' action.
322      *
323      * @param props the request properties for this action. Ignored.
324      *
325      */

326     public boolean logout(Properties JavaDoc props) {
327     me = "nobody";
328     isAdmin = isManager = isDeveloper = isUser = false;
329     if (conn != null) {
330         try {
331         conn.close();
332         } catch (Throwable JavaDoc t) {}
333         conn = null;
334     }
335     return true;
336     }
337
338     /**
339      * Execute the 'login' action.
340      *
341      * @param props the request properties for this action.
342      * <dl>
343      * <dt>username</dt><dd>The user's login name</dd>
344      * <dt>password</dt><dd>The user's password</dd>
345      * </dl>
346      *
347      * @exception SQLException may be thrown
348      */

349     public boolean login(Properties JavaDoc props) throws SQLException JavaDoc {
350     String JavaDoc user = getString(props, "username");
351     String JavaDoc pass = getString(props, "password");
352     getConnection();
353     Statement JavaDoc s = conn.createStatement();
354     try {
355         ResultSet JavaDoc rs = s.executeQuery(
356         "select * from person where name = '" + user +
357         "' and password = '" + pass + "'");
358         try {
359         if (rs.next()) {
360             me = user;
361             my_person_type = rs.getString("person_type");
362             isAdmin = my_person_type.equals("Administrator");
363             isManager = isAdmin || my_person_type.equals("Manager");
364             isDeveloper = isManager || my_person_type.equals("Developer");
365             isUser = isDeveloper || my_person_type.equals("User");
366             return true;
367         }
368         } finally {
369         rs.close();
370         }
371     } finally {
372         s.close();
373     }
374     return false;
375     }
376
377     /**
378      * Return the next integer in the specified sequence.
379      *
380      * @return the next integer in this sequence.
381      * @exception SQLException may be thrown
382      */

383     int getNextId(String JavaDoc type) throws SQLException JavaDoc {
384     Statement JavaDoc s = conn.createStatement(
385         ResultSet.TYPE_SCROLL_SENSITIVE,
386         ResultSet.CONCUR_UPDATABLE);
387     try {
388         int ret = 0;
389         ResultSet JavaDoc rs = s.executeQuery(
390         "select ivalue from singleton where name = '" + type + "'");
391         try {
392         if (rs.next()) {
393             ret = rs.getInt(1);
394             rs.updateInt(1, ret + 1);
395             rs.updateRow();
396         }
397         } finally {
398         rs.close();
399         }
400         return ret;
401     } finally {
402         s.close();
403     }
404     }
405
406     /**
407      * Return the number of records in the bug history for the specified
408      * bug.
409      *
410      * @param bug_id the bug number
411      * @return the number of history records for this bug.
412      * @exception SQLException may be thrown
413      */

414     int getBugHistSize(int bug_id) throws SQLException JavaDoc {
415     getBugHist.clearParameters();
416     getBugHist.setInt(1, bug_id);
417     ResultSet JavaDoc rs = getBugHist.executeQuery();
418     try {
419         if (rs.next()) {
420         int ret = rs.getInt(1) + 1;
421         rs.updateInt(1, ret);
422         rs.updateRow();
423         return ret;
424         } else {
425         throw new SQLException JavaDoc("no bug: " + bug_id);
426         }
427     } finally {
428         rs.close();
429     }
430     }
431
432     /**
433      * Execute the 'addUser' action.
434      *
435      * @param props the request properties for this action:<p>
436      * <dl>
437      * <dt>name</dt><dd>The user's login name</dd>
438      * <dt>password</dt><dd>The user's password</dd>
439      * <dt>password2</dt><dd>The user's password confirmation</dd>
440      * <dt>email</dt><dd>The user's email address</dd>
441      * <dt>person_type</dt><dd>The user's 'class', one of
442      * <ul><li>User</li>
443      * <li>Developer</li>
444      * <li>Manager</li>
445      * <li>Administrator</li>
446      * </ul></dt>
447      * </dl>
448      *
449      * @exception SQLException may be thrown
450      */

451     public boolean addUser(Properties JavaDoc props)
452     throws SQLException JavaDoc, ServletException JavaDoc
453     {
454     String JavaDoc p1 = getString(props, "password");
455     String JavaDoc p2 = getString(props, "password2");
456     if (!p1.equals(p2)) {
457         throw new ServletException JavaDoc(
458         "Password doesn't match confirm password");
459     }
460     insertPerson.clearParameters();
461     insertPerson.setString(1, getString(props, "name"));
462     insertPerson.setString(2, getString(props, "password"));
463     insertPerson.setString(3, getString(props, "email"));
464     
465     String JavaDoc person_type = "User";
466     if (isAdmin) {
467         String JavaDoc t = getString(props, "person_type");
468         if (t != null && t.length() > 0) person_type = t;
469     }
470     insertPerson.setString(4, person_type);
471         
472     return 1 == insertPerson.executeUpdate();
473     }
474
475     /**
476      * Execute the 'updateUser' action.
477      * @param props the request properties for this action:<p>
478      * <dl>
479      * <dt>name</dt><dd>The user's login name</dd>
480      * <dt>password</dt><dd>The user's password</dd>
481      * <dt>email</dt><dd>The user's email address</dd>
482      * <dt>person_type</dt><dd>The user's 'class', one of
483      * <ul><li>User</li>
484      * <li>Developer</li>
485      * <li>Manager</li>
486      * <li>Administrator</li>
487      * </ul></dt>
488      * </dl>
489      *
490      * @exception SQLException may be thrown
491      */

492     public boolean updateUser(Properties JavaDoc p) throws SQLException JavaDoc {
493     updateUser.clearParameters();
494     updateUser.setString(1, p.getProperty("name"));
495     ResultSet JavaDoc rs = updateUser.executeQuery();
496         try {
497             if (rs.next()) {
498                 if (!p.getProperty("password").equals("password")) {
499                     rs.updateString("password", p.getProperty("password"));
500                 }
501                 rs.updateString("email", p.getProperty("email"));
502                 rs.updateString("person_type", p.getProperty("person_type"));
503                 rs.updateRow();
504                 return true;
505             } else {
506                 return false;
507             }
508         } finally {
509             rs.close();
510         }
511     }
512
513     /**
514      * Execute the 'deleteUser' action
515      *
516      * @exception SQLException may be thrown
517      */

518     public boolean deleteUser(Properties JavaDoc p) throws SQLException JavaDoc {
519     deleteUser.clearParameters();
520     deleteUser.setString(1, p.getProperty("name"));
521     return deleteUser.executeUpdate() == 1;
522     }
523     
524     /**
525      * Generate an HTML <code>&lt;SELECT&gt;</code> element listing all
526      * elements in the specified table.
527      *
528      * @param type the table (e.g., priority, state, etc.)
529      * @return the HTML string.
530      */

531     public String JavaDoc listOptions(String JavaDoc type)
532     throws ServletException JavaDoc
533     {
534     return listOptions(type, null);
535     }
536
537     /**
538      * Generate an HTML <code>&lt;SELECT&gt;</code> element listing all
539      * elements in the specified table.
540      *
541      * @param type the table (e.g., priority, state, etc.) Also the name
542      * of the SELECT element, and the name of the column.
543      * @param sel if non null, the value to be initially selected
544      * @return the HTML string.
545      */

546     public String JavaDoc listOptions(String JavaDoc type, String JavaDoc sel)
547     throws ServletException JavaDoc
548     {
549     return listOptions(type, type, sel);
550     }
551
552     /**
553      * Generate an HTML <code>&lt;SELECT&gt;</code> element listing all
554      * elements in the specified table.
555      *
556      * @param table the table (e.g., priority, state, etc.) Also the name
557      * of the SELECT element.
558      * @param type the name of the column containing the enumerated values.
559      * @param sel if non null, the value to be initially selected
560      * @return the HTML string.
561      */

562     public String JavaDoc listOptions(String JavaDoc table, String JavaDoc type, String JavaDoc sel)
563     throws ServletException JavaDoc
564     {
565     return listOptions(table, table, type, sel);
566     }
567
568     /**
569      * Generate an HTML <code>&lt;SELECT&gt;</code> element listing all
570      * elements in the specified table.
571      *
572      * @param selType the name of the SELECT widget.
573      * @param table the table (e.g., priority, state, etc.)
574      * @param type the name of the column containing the enumerated values.
575      * @param sel if non null, the value to be initially selected
576      * @return the HTML string.
577      */

578     public String JavaDoc listOptions(String JavaDoc seltype, String JavaDoc table,
579                   String JavaDoc type, String JavaDoc sel)
580     throws ServletException JavaDoc
581     {
582     try {
583         Statement JavaDoc s = conn.createStatement();
584         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("\n<select name=\"");
585         sb.append(seltype);
586         sb.append("\">");
587         try {
588         ResultSet JavaDoc rs = s.executeQuery("select " + type +
589                           " from " + table);
590         try {
591             while (rs.next()) {
592             String JavaDoc t = rs.getString(1);
593             sb.append("\n <option value=\"");
594             sb.append(t);
595             sb.append('"');
596             if (sel != null && t.equals(sel)) {
597                 sb.append(" selected");
598             }
599             sb.append(">");
600             sb.append(t);
601             sb.append("</option>");
602             }
603         } finally {
604             rs.close();
605         }
606         sb.append("</select>");
607         return sb.toString();
608         } finally {
609         s.close();
610         }
611     } catch (SQLException JavaDoc e) {
612         throw new ServletException JavaDoc(e.toString());
613     }
614     }
615
616     /**
617      * Generate an HTML <code>&lt;SELECT&gt;</code> element listing all
618      * users.
619      *
620      * @param type the name of the SELECT element.
621      * @param sel the value (if any) to be initially selected.
622      */

623     public String JavaDoc listUsers(String JavaDoc type, String JavaDoc sel) throws ServletException JavaDoc {
624     return listOptions(type, "person", "name", sel);
625     }
626
627     /**
628      * Return the name of the user who owns the specified component.
629      *
630      * @param component the component name
631      * @return the component's owner
632      * @exception SQLException may be thrown
633      * @exception ServletException may be thrown
634      */

635     public String JavaDoc getComponentOwner(String JavaDoc component)
636     throws SQLException JavaDoc, ServletException JavaDoc
637     {
638     synchronized (getComponentOwner) {
639         getComponentOwner.clearParameters();
640         getComponentOwner.setString(1, component);
641         ResultSet JavaDoc rs = getComponentOwner.executeQuery();
642         try {
643         if (rs.next()) {
644             return rs.getString(1);
645         } else {
646             return "nobody";
647         }
648         } finally {
649         rs.close();
650         }
651     }
652     }
653     
654     /**
655      * Return an integer valued property
656      *
657      * @param props a properties object
658      * @param name the name of the property to retrieve.
659      * @return the property value
660      * @exception ServletException is thrown if the property isn't a valid
661      * integer.
662      */

663     static int getInt(Properties JavaDoc props, String JavaDoc name) throws ServletException JavaDoc {
664     try {
665         return Integer.parseInt(props.getProperty(name));
666     } catch (Throwable JavaDoc e) {
667         throw new ServletException JavaDoc("Missing or malformed parameter: " +
668                        name);
669     }
670     }
671
672     /**
673      * Return a string-valued property.
674      *
675      * @param props a properties object
676      * @param name the name of the property to retrieve.
677      * @return the property value, or the empty string if the property
678      * isn't defined.
679      */

680     static String JavaDoc getString(Properties JavaDoc props, String JavaDoc name) {
681     String JavaDoc s = props.getProperty(name);
682     if (s == null) return "";
683     return s;
684     }
685     
686     /**
687      * Execute the 'addBug' action.
688      *
689      * @param props the request properties, contains values for the various
690      * fields in the 'bug' and 'bug_history' tables.
691      *
692      * @return true if this action succeeded.
693      * @exception ServletException may be thrown.
694      */

695     public boolean addBug(Properties JavaDoc props) throws ServletException JavaDoc {
696     if (!isUser()) throw new ServletException JavaDoc("not logged in");
697     try {
698         Statement JavaDoc s = conn.createStatement();
699         try {
700         int bug_id = getNextId("bug");
701         int ret = s.executeUpdate(
702             "insert into bug(bug_id, hist_size) values(" +
703             bug_id + ",0)");
704         if (ret != 1) {
705             throw new ServletException JavaDoc("add bug failed");
706         }
707
708         String JavaDoc component = getString(props, "component");
709         String JavaDoc owner = getComponentOwner(component);
710
711         insertBugHist.clearParameters();
712         insertBugHist.setInt(1, bug_id); // bug_id
713
insertBugHist.setInt(2, 0); // hist_pos
714
insertBugHist.setString(3, me); // submitter
715
insertBugHist.setString(4, getString(props, "abstract"));
716         insertBugHist.setString(5, getString(props, "description"));
717         insertBugHist.setString(6, getString(props, "comments"));
718         insertBugHist.setString(7, "Active"); // state
719
insertBugHist.setString(8, getString(props, "priority"));
720         insertBugHist.setString(9, getString(props, "type"));
721         insertBugHist.setString(10, owner); // owner
722
insertBugHist.setString(11, component); // component
723
insertBugHist.setTimestamp(12, now()); // modtime
724
ret = insertBugHist.executeUpdate();
725         if (ret != 1) {
726             throw new ServletException JavaDoc("add bug history failed, ret = " + ret);
727         }
728         return true;
729         } finally {
730         s.close();
731         }
732     } catch (SQLException JavaDoc e) {
733         throw new ServletException JavaDoc(e.toString());
734     }
735     }
736
737     /**
738      * Execute the 'updateBug' action.
739      *
740      * @param props the request properties, contains values for the various
741      * fields in the 'bug' and 'bug_history' tables.
742      *
743      * @return true if this action succeeded.
744      * @exception ServletException may be thrown.
745      */

746     public boolean updateBug(Properties JavaDoc props) throws ServletException JavaDoc {
747     if (!isUser()) throw new ServletException JavaDoc("not logged in");
748     try {
749         int bug_id = getInt(props, "bug_id");
750         int hist_pos = getBugHistSize(bug_id);
751
752         String JavaDoc component = getString(props, "component");
753         String JavaDoc owner = getComponentOwner(component);
754
755         insertBugHist.clearParameters();
756         insertBugHist.setInt(1, bug_id); // bug_id
757
insertBugHist.setInt(2, hist_pos); // hist_pos
758
insertBugHist.setString(3, me); // submitter
759
insertBugHist.setString(4, getString(props, "abstract"));
760         insertBugHist.setString(5, getString(props, "description"));
761         insertBugHist.setString(6, getString(props, "comments"));
762         insertBugHist.setString(7, getString(props, "state"));
763         insertBugHist.setString(8, getString(props, "priority"));
764         insertBugHist.setString(9, getString(props, "type"));
765         insertBugHist.setString(10, getString(props, "owner"));
766         insertBugHist.setString(11, getString(props, "component"));
767         insertBugHist.setTimestamp(12, now()); // modtime
768
if (insertBugHist.executeUpdate() != 1) {
769         throw new ServletException JavaDoc("update bug history failed");
770         }
771         return true;
772     } catch (SQLException JavaDoc e) {
773         throw new ServletException JavaDoc(e.toString());
774     }
775     }
776
777     /**
778      * Make a sql timestamp value representing the current time.
779      *
780      * @return a timestamp value.
781      */

782     static final java.sql.Timestamp JavaDoc now() {
783     return new java.sql.Timestamp JavaDoc(System.currentTimeMillis());
784     }
785
786     /**
787      * Utility to do URL decoding without any exception handling.
788      * Lazy bastard.
789      * @param s the url to decode
790      * @return the decoded url
791      */

792     public final String JavaDoc urlDecode(String JavaDoc s) {
793     try {
794         if (s == null) return "";
795         return java.net.URLDecoder.decode(s);
796     } catch (Throwable JavaDoc e) {
797         return s;
798     }
799     }
800
801     /**
802      * Perform the bug search operation.
803      *
804      * @param query the query string, a boolean predicate selecting bugs
805      * to be returned.
806      * @param ob an optional column name to use with an 'order by' clause,
807      * to cause the list of bugs to be sorted based on that column.
808      * @return a <code>Vector</code> of <code>Properties</code> objects,
809      * where each Properties element contains entries for each column
810      * in the search result.
811      * @exception ServletException may be thrown
812      */

813     public Vector JavaDoc searchBugs(String JavaDoc query, String JavaDoc ob) throws ServletException JavaDoc {
814     Vector JavaDoc v = new Vector JavaDoc();
815     try {
816         Statement JavaDoc s = conn.createStatement();
817         if (query == null) query = "";
818         query = query.trim();
819         if (query.length() > 0) {
820         query = "and " + query;
821         }
822         if (ob != null) {
823         query = query + " order by " + ob;
824         }
825         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
826         sb.append("select * from bug natural join bug_history where ");
827         sb.append("(hist_size = hist_pos) " + query);
828         ResultSet JavaDoc rs = s.executeQuery(sb.toString());
829         ResultSetMetaData JavaDoc rm = rs.getMetaData();
830         try {
831         while (rs.next()) {
832             Properties JavaDoc p = new Properties JavaDoc();
833             for (int i = 1; i <= rm.getColumnCount(); i++) {
834             String JavaDoc name = rm.getColumnLabel(i);
835             Object JavaDoc obj = rs.getObject(i);
836             String JavaDoc val = (obj == null) ? "" : obj.toString();
837             p.put(name.toLowerCase(), val);
838             }
839             v.addElement(p);
840         }
841         } finally {
842         rs.close();
843         }
844     } catch (SQLException JavaDoc e) {
845         throw new ServletException JavaDoc(e.toString());
846     } catch (Throwable JavaDoc t) {
847         t.printStackTrace(System.out);
848     }
849     return v;
850     }
851
852     /**
853      * Turn the current row in the result set into a Hashtable.
854      *
855      * @param rs a result set
856      * @return a Hashtable where the keys are the string-valued column labels
857      * of the result set and the values are the string-valued column values
858      * from the current row of the result set.
859      *
860      * @exception SQLException may be thrown
861      */

862     final Hashtable JavaDoc getProps(ResultSet JavaDoc rs) throws SQLException JavaDoc {
863     Hashtable JavaDoc p = new Hashtable JavaDoc();
864     ResultSetMetaData JavaDoc rm = rs.getMetaData();
865     for (int i = 1; i <= rm.getColumnCount(); i++) {
866         String JavaDoc name = rm.getColumnLabel(i);
867         String JavaDoc val = String.valueOf(rs.getObject(i));
868         p.put(name.toLowerCase(), val);
869     }
870     return p;
871     }
872
873     /**
874      * Return a list of valid users, as a Vector of Properties objects,
875      * where each Hashtable object contains all of the user's properties
876      * (except the password!)
877      *
878      * @return a list of valid users
879      * @exception SQLException may be thrown
880      */

881     public Vector JavaDoc getUsers() throws SQLException JavaDoc {
882     Vector JavaDoc v = new Vector JavaDoc();
883     Statement JavaDoc s = conn.createStatement();
884     try {
885         ResultSet JavaDoc rs = s.executeQuery("select * from person");
886         try {
887         while (rs.next()) {
888             Hashtable JavaDoc t = getProps(rs);
889             t.remove("password");
890             v.addElement(t);
891         }
892         } finally {
893         rs.close();
894         }
895     } finally {
896         s.close();
897     }
898     return v;
899     }
900
901     /**
902      * Return a list of valid project/components, as a Vector of Hashtable
903      * objects,
904      * where each Hashtable object contains all of the user's properties
905      * (except the password!)
906      *
907      * @return a list of valid components
908      * @exception SQLException may be thrown
909      */

910     public Vector JavaDoc getProjects() throws SQLException JavaDoc {
911     Vector JavaDoc v = new Vector JavaDoc();
912     Statement JavaDoc s = conn.createStatement();
913     try {
914         ResultSet JavaDoc rs = s.executeQuery("select * from component");
915         try {
916         while (rs.next()) {
917             Hashtable JavaDoc t = getProps(rs);
918             v.addElement(t);
919         }
920         } finally {
921         rs.close();
922         }
923     } finally {
924         s.close();
925     }
926     return v;
927     }
928
929     /**
930      * Return the properties for a single user.
931      *
932      * @param user the user name
933      * @return the user's properties (except the password)
934      * @exception SQLException may be thrown
935      */

936     public Hashtable JavaDoc getUser(String JavaDoc user) throws SQLException JavaDoc {
937     getUser.clearParameters();
938     getUser.setString(1, user);
939     ResultSet JavaDoc rs = getUser.executeQuery();
940     try {
941         if (rs.next()) {
942         Hashtable JavaDoc t = getProps(rs);
943         t.remove("password");
944         return t;
945         } else {
946         return null;
947         }
948     } finally {
949         rs.close();
950     }
951     }
952
953     /**
954      * Return the properties for a single component.
955      *
956      * @param name the component name
957      * @return the component's properties
958      * @exception SQLException may be thrown
959      */

960     public Hashtable JavaDoc getProject(String JavaDoc user) throws SQLException JavaDoc {
961     getProject.clearParameters();
962     getProject.setString(1, user);
963     ResultSet JavaDoc rs = getProject.executeQuery();
964     try {
965         if (rs.next()) {
966         Hashtable JavaDoc t = getProps(rs);
967         return t;
968         } else {
969         return null;
970         }
971     } finally {
972         rs.close();
973     }
974     }
975
976     /**
977      * Execute the 'newProject' action.
978      *
979      * @param props the request properties for this action:<p>
980      * <dl>
981      * <dt>component</dt><dd>The name of the project</dd>
982      * <dt>owner</dt><dd>The owner of the project.</dd>
983      * </dl>
984      *
985      * @exception SQLException may be thrown
986      */

987     public boolean newProject(Properties JavaDoc p) throws SQLException JavaDoc {
988     newProject.clearParameters();
989     newProject.setString(1, p.getProperty("component"));
990     newProject.setString(2, p.getProperty("owner"));
991     return 1 == newProject.executeUpdate();
992     }
993
994     /**
995      * Execute the 'updateProject' action.
996      * @param props the request properties for this action:<p>
997      * <dl>
998      * <dt>component</dt><dd>The name of the project</dd>
999      * <dt>owner</dt><dd>The owner of the project.</dd>
1000     * </dl>
1001     *
1002     * @exception SQLException may be thrown
1003     */

1004    public boolean updateProject(Properties JavaDoc p) throws SQLException JavaDoc {
1005    updateProject.clearParameters();
1006    updateProject.setString(1, p.getProperty("component"));
1007    ResultSet JavaDoc rs = updateProject.executeQuery();
1008        try {
1009            if (rs.next()) {
1010                rs.updateString("owner", p.getProperty("owner"));
1011                rs.updateRow();
1012                return true;
1013            } else {
1014                return false;
1015            }
1016        } finally {
1017            rs.close();
1018        }
1019    }
1020
1021    /**
1022     * Execute the 'deleteProject' action
1023     *
1024     * @exception SQLException may be thrown
1025     */

1026    public boolean deleteProject(Properties JavaDoc p) throws SQLException JavaDoc {
1027    deleteProject.clearParameters();
1028    deleteProject.setString(1, p.getProperty("component"));
1029    return deleteProject.executeUpdate() == 1;
1030    }
1031    
1032    /**
1033     * The properties that we ignore when computing deltas between
1034     * successive bug history records.
1035     */

1036    static Hashtable JavaDoc nonDeltas = new Hashtable JavaDoc();
1037    static {
1038    nonDeltas.put("modtime", "");
1039    nonDeltas.put("comments", "");
1040    }
1041
1042    /**
1043     * Given two bug history records, return a hashtable containing entries
1044     * for each field which changed between the two records.
1045     *
1046     * @param a the newer history record
1047     * @param b the older history record
1048     * @return a Hashtable where the keys are the names of the changed fields
1049     * and the values are strings of the form:<p>
1050     * <pre>Changed from <i>bval</i> to <i>aval</i></pre>
1051     */

1052    Hashtable JavaDoc diffProps(Hashtable JavaDoc a, Hashtable JavaDoc b) {
1053    Hashtable JavaDoc t = new Hashtable JavaDoc();
1054    Enumeration JavaDoc e = a.keys();
1055    while (e.hasMoreElements()) {
1056        String JavaDoc key = (String JavaDoc)e.nextElement();
1057        if (key.equals("history")) continue;
1058        if (key.equals("hist_pos")) continue;
1059        String JavaDoc aval = (String JavaDoc)a.get(key);
1060        String JavaDoc bval = (String JavaDoc)b.get(key);
1061        if (!aval.equals(bval)) {
1062        if (nonDeltas.get(key) != null) {
1063            t.put(key, bval);
1064        } else {
1065            t.put(key, "Changed from " + bval + " to " + aval);
1066        }
1067        }
1068    }
1069    return t;
1070    }
1071
1072    /**
1073     * Return the current information and history for the specified bug.
1074     *
1075     * @param bug_id
1076     * @return a Hashtable where the keys are the names of the bug
1077     * properties and the values are the current (i.e., most recent)
1078     * values for those properties. The special key <i>"history"</i>
1079     * has a Vector of Hashtables value containing the reverse-chronological
1080     * history deltas for the bug.
1081     *
1082     * @exception ServletException may be thrown
1083     */

1084    public Hashtable JavaDoc getBug(String JavaDoc bug_id) throws ServletException JavaDoc {
1085    try {
1086        getBug.clearParameters();
1087        getBug.setInt(1, Integer.parseInt(bug_id));
1088        ResultSet JavaDoc rs = getBug.executeQuery();
1089        try {
1090        Hashtable JavaDoc ret = null;
1091        Vector JavaDoc hist = new Vector JavaDoc();
1092        Hashtable JavaDoc last = null;
1093        String JavaDoc description = "";
1094        while (rs.next()) {
1095            Hashtable JavaDoc props = getProps(rs);
1096            description = rs.getString("Description");
1097            if (ret == null) {
1098            ret = props;
1099            ret.put("history", hist);
1100            } else {
1101            hist.addElement(diffProps(last, props));
1102            }
1103            last = props;
1104        }
1105        // take the 'last' description. Cause the results are returned
1106
// newest first, this gives us the original bug description.
1107
if (ret == null) ret = new Hashtable JavaDoc();
1108        ret.put("description", description);
1109        return ret;
1110        } finally {
1111        rs.close();
1112        }
1113    } catch (SQLException JavaDoc e) {
1114        throw new ServletException JavaDoc(e.toString());
1115    }
1116    }
1117
1118    /**
1119     * Replace occurrences of &lt;, &gt;, and &amp; with their HTML
1120     * entity-representation equivalents.
1121     *
1122     * @param the the string to encode
1123     * @return the encoded string
1124     */

1125    public String JavaDoc htmlEncode(String JavaDoc s) {
1126    try {
1127        ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
1128        PrintWriter JavaDoc pw = new PrintWriter JavaDoc(bos);
1129        HtmlWriter w = new HtmlWriter(pw);
1130        for (int i = 0; i < s.length(); i++) {
1131        w.write(s.charAt(i));
1132        }
1133        w.flush();
1134        return bos.toString();
1135    } catch (Exception JavaDoc e) {
1136        return s;
1137    }
1138    }
1139
1140    /**
1141     * The main request handler. Determine which action is to be invoked
1142     * and dispatch the appropriate routine.
1143     *
1144     * @param req the http request
1145     * @exception ServletException may be thrown
1146     * @exception SQLException may be thrown
1147     */

1148    public void handleRequest(HttpServletRequest JavaDoc req)
1149    throws ServletException JavaDoc, SQLException JavaDoc
1150    {
1151    String JavaDoc action = req.getParameter("action");
1152        boolean commit = false;
1153        try {
1154            if (action != null) {
1155                Properties JavaDoc p = getRequestProperties(req);
1156                if (action.equals("login")) {
1157                    commit = login(p);
1158                } else if (action.equals("logout")) {
1159                    commit = logout(p);
1160                } else if (!isUser()) {
1161                    throw new ServletException JavaDoc("not logged in");
1162                } else if (action.equals("newbug")) {
1163                    commit = addBug(p);
1164                } else if (action.equals("modify")) {
1165                    commit = updateBug(p);
1166                } else if (action.equals("register")) {
1167                    commit =addUser(p);
1168                } else if (action.equals("updateUser")) {
1169                    commit = updateUser(p);
1170                } else if (action.equals("deleteUser")) {
1171                    commit = deleteUser(p);
1172                } else if (action.equals("newUser")) {
1173                    commit = addUser(p);
1174                } else if (action.equals("newProject")) {
1175                    commit = newProject(p);
1176                } else if (action.equals("updateProject")) {
1177                    commit = updateProject(p);
1178                } else if (action.equals("deleteProject")) {
1179                    commit = deleteProject(p);
1180                } else if (action.equals("noop")) {
1181                } else {
1182                    throw new ServletException JavaDoc("Bad action: " + action);
1183                }
1184            } else if (!isUser()) {
1185                throw new ServletException JavaDoc("not logged in");
1186            }
1187        } finally {
1188// if (commit && conn != null) {
1189
// conn.commit();
1190
// } else {
1191
// conn.rollback();
1192
// }
1193
}
1194    }
1195
1196    /**
1197     * Build a Properties object containing all of the request parameters.
1198     *
1199     * @param req the http request
1200     * @return the request parameters
1201     */

1202    public Properties JavaDoc getRequestProperties(HttpServletRequest JavaDoc req) {
1203    Properties JavaDoc p = new Properties JavaDoc();
1204    Enumeration JavaDoc e = req.getParameterNames();
1205    while (e.hasMoreElements()) {
1206        String JavaDoc name = (String JavaDoc)e.nextElement();
1207        String JavaDoc val = req.getParameter(name);
1208        try {
1209        val = URLDecoder.decode(val);
1210        } catch (Throwable JavaDoc ex) {}
1211        p.put(name, val);
1212    }
1213    return p;
1214    }
1215}
1216
Popular Tags