DatabaseConnection.java
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:18k
源码类别:

mpeg/mp3

开发平台:

C/C++

  1. /* Copyright (C) 1998, 1999 State University of New York at Stony Brook
  2.    Author: Andrew V. Shuvalov ( andrew@ecsl.cs.sunysb.edu )
  3.    Software license is located in file "COPYING"
  4.    VideoServer application
  5.      $Id: DatabaseConnection.java,v 1.21 1999/03/13 03:06:34 andrew Exp $
  6. */
  7. package edu.sunysb.cs.ecsl.videoserver;
  8. import java.io.*;
  9. import java.net.*;
  10. import java.sql.*;
  11. import java.text.*;
  12. import java.util.Vector;
  13. import java.util.Calendar;
  14. import java.util.Date;
  15. /** interface with database
  16.  */
  17. class DatabaseConnection implements TextProtocol {
  18.   VSProperties props = null; 
  19.   Connection dbConnection = null;
  20.   /** class to operate the database as a whole */
  21.   DatabaseMetaData dbmd = null;
  22.   /** this name is set first to default, next can be modified
  23.    */
  24.   protected String currentDatabaseName = null;
  25.  
  26.   /** parent thread */
  27.   VideoServerThread parent_thread;
  28.   protected VideoServer application = null;
  29.   /** formatter for date/time for all functions */
  30.   SimpleDateFormat dateFormat;
  31.   protected DatabaseConnection( VideoServerThread vst, 
  32. VideoServer appl,
  33. DataOutputStream outputStream )
  34.     throws IOException, SQLException {
  35.     parent_thread = vst;
  36.     application = appl;
  37.     props = VSProperties.GetPropertiesInstance();
  38.     dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss zzz");
  39.     try {
  40.       connect( props.getProperty( props.DatabaseName ) );
  41.     } catch ( ClassNotFoundException e ) {
  42.       throw new SQLException( e.toString() );
  43.     }
  44.   }
  45.   protected void connect( String dbname )
  46.     throws SQLException, ClassNotFoundException {
  47.     currentDatabaseName = new String( dbname );
  48.     String db = new String( props.getProperty( props.DatabaseEngine ) 
  49.     + ":" + dbname );
  50.     
  51.     //  --- Load the driver
  52.     try
  53.       {
  54. Class.forName( props.getProperty(props.DatabaseEngineClassName));
  55.       } catch (ClassNotFoundException e) {
  56. System.err.println("Exception: " + e.toString());
  57. parent_thread.debug_forced("Exception: " + e.toString());
  58. throw new ClassNotFoundException( e.toString() );
  59.       }
  60.     if( dbConnection != null ) 
  61.       {
  62. dbConnection.close();
  63. dbmd = null;
  64.       }
  65.     dbConnection = DriverManager.getConnection
  66.       ( db, props.getProperty( props.DatabaseUserName ), "" );
  67.     dbmd = dbConnection.getMetaData();
  68.     parent_thread.debug( "connected to the database " + dbname, 1 );
  69.   }
  70.   /** the hole database entities format is hard-coded here. I see no reason
  71.       to put this is some kind of configuration
  72.   */
  73.   private void create_new_database()
  74.     throws SQLException, ClassNotFoundException {
  75.     if( dbConnection == null ) 
  76.       return;
  77.       
  78.     parent_thread.debug_forced("Creating new database "+currentDatabaseName);
  79.     Statement s;
  80.     try {
  81.       s = dbConnection.createStatement();
  82.       s.execute( "DROP TABLE moviefiles, movies, captions" );
  83.       s.close();
  84.     } catch( SQLException e ) {
  85.       // that's ok, that means nothing to drop
  86.     }
  87.       
  88.     s = dbConnection.createStatement();
  89.     s.execute( "CREATE TABLE moviefiles ( " +
  90.        //  -- uniqely generated from title 
  91.        //  -- it may be several moviefiles with this id
  92.        "id      int, " +
  93.        // -- uniqely identify the push server which holds this movie
  94.        "pushserv_id int, " +
  95.        // -- store the relative path of file, not from root
  96.        "mpegfile        varchar(255), " +
  97.        "starttm           timestamp, " +
  98.        "stoptm            timestamp " +
  99.        ") " );
  100.     s.close();
  101.       
  102.     s = dbConnection.createStatement();
  103.     s.execute( "CREATE TABLE movies ( " +
  104.        //   -- Title must be unique
  105.        "title   varchar(100), " + 
  106.        // -- uniqely generated from title and used
  107.        // -- in moviefile
  108.        "id      int, " +
  109.        // -- comments
  110.        "description     text, " +
  111.        "starttm         timestamp, " +
  112.        "stoptm          timestamp )" );
  113.     s.close();
  114.     s = dbConnection.createStatement();
  115.     s.execute( "CREATE TABLE captions ( " +
  116.        // -- movie id
  117.        "id      int, " +
  118.        "text    varchar(255), " +
  119.        "captime timestamp )" );
  120.     s.close();
  121.   }
  122.   protected void finalize() throws Throwable {
  123.     dbConnection.close();
  124.   }
  125.   /** set or ask database name 
  126.    */
  127.   protected void database_impl( Vector args, BufferedReader inputReader, 
  128. DataOutputStream outputStream,
  129. boolean SuperuserStatus ) 
  130.     throws SyntaxException, SQLException, IOException {
  131.     if( dbConnection == null ) 
  132.       {
  133. parent_thread.debug_forced( "!Not connected" );
  134. outputStream.writeBytes( "->n" + _disconnect_[KEY] + "n<-n" );
  135. return;
  136.       }
  137.     // ask the currently connected database name
  138.     if( args.size() == 1 ) { 
  139.       outputStream.writeBytes( "->n" + currentDatabaseName + "n<-n" );
  140.     }
  141.     else if( args.size() == 2 ) {
  142.       application.log( 1, "connecting to another database " + 
  143.        args.elementAt( 1 ) );
  144.       try {
  145. connect( ((String)args.elementAt( 1 )).trim() );
  146. outputStream.writeBytes( "->n"+currentDatabaseName+"n<-n" );
  147. application.log( 2, "connected" ); 
  148.       } catch( SQLException e ) {
  149. application.log( 1, e.toString() );
  150. parent_thread.debug_forced( e.toString() );
  151. outputStream.writeBytes( "->n" + _disconnect_[KEY] + 
  152.  "n<-n" );
  153. return;
  154.       } catch ( ClassNotFoundException e ) {
  155. // that's fatal
  156. application.log( 1, e.toString() );
  157. parent_thread.debug_forced( e.toString() );
  158. outputStream.writeBytes( "->n" + _disconnect_[KEY] + 
  159.  "n<-n" );
  160. return;
  161.       }
  162.     }
  163.     else 
  164.       throw new SyntaxException
  165. (_database_name_[KEY]+" command accepts only 0 or 1 parameters");
  166.     // test if this database is initialised. If not - do it.
  167.     try {
  168.       Statement s;
  169.       ResultSet rs;
  170.       s = dbConnection.createStatement();
  171.       rs = s.executeQuery("select * from movies");
  172.       s.close();
  173.     } catch( SQLException e ) {
  174.       if( SuperuserStatus ) {
  175. // superuser have the right to create the new database
  176. try {
  177.   create_new_database();
  178. } catch( Exception ex ) { 
  179.   // any
  180.   application.log( 1, ex.toString() );
  181.   parent_thread.debug_forced( ex.toString() );
  182.   outputStream.writeBytes( "->n" + _disconnect_[KEY] + 
  183.    "n<-n" );
  184. }
  185.       }
  186.       else {
  187. // there is nothing i can do 
  188. application.log( 1, "only superuser may " +
  189.  "initialize new database" );
  190. parent_thread.debug_forced( "only superuser may " +
  191.     "initialize new database" );
  192. outputStream.writeBytes( "->n" + _disconnect_[KEY] + 
  193.  "n<-n" );
  194. return;
  195.       }
  196.     }
  197.   }
  198.   /** list movies in database */
  199.   protected void listmovies_impl( Vector args, BufferedReader inputReader, 
  200.        DataOutputStream outputStream,
  201.        boolean SuperuserStatus ) 
  202.     throws SyntaxException, SQLException, IOException {
  203.     if( dbConnection == null ) 
  204.       {
  205. parent_thread.debug_forced("!Not connectedn");
  206. outputStream.writeBytes( "->n" + _disconnect_[KEY] + "n<-n" );
  207. return;
  208.       }
  209.     
  210.     try {
  211.       Statement s;
  212.       ResultSet rs;
  213.       s = dbConnection.createStatement();
  214.       rs = s.executeQuery("select title, id, description, " +
  215.   "starttm, stoptm from movies");
  216.       outputStream.writeBytes( "->n" );
  217.       if( rs == null )
  218. throw new SQLException( "got null in reply to execute query" );
  219.       while( rs.next() ) {
  220. String title = rs.getString( "title" );
  221. int id = rs.getInt( "id" );
  222. String comments = rs.getString( "description" );
  223. // it may be null !
  224. // comments may have 0 or several lines of text,
  225. // so first transfer the line count
  226. Vector comm_lines = new Vector();
  227. if( comments != null )
  228.   {
  229.     int pos = 0;
  230.     int pos_end = 0;
  231.     while( true )
  232.       {
  233. pos_end = comments.indexOf( 'n', pos );
  234. if( pos_end == -1 )
  235.   {
  236.     String line = comments.substring( pos );
  237.     comm_lines.addElement( line );
  238.     break;
  239.   }
  240. else
  241.   {
  242.     String line = comments.substring( pos, pos_end );
  243.     comm_lines.addElement( line );
  244.     pos = pos_end;
  245.   }
  246.       }
  247.   }
  248. Date time1stamp = rs.getTimestamp( "starttm" );
  249. Date time2stamp = rs.getTimestamp( "stoptm" );
  250. if( time2stamp == null )
  251.   {
  252.     application.log( 3, "unfinished movie #" + String.valueOf( id ));
  253.     time2stamp = Calendar.getInstance().getTime();
  254.   }
  255. outputStream.writeBytes( title + "n" + id + "n" );
  256. outputStream.writeBytes( comm_lines.size() + "n" );
  257. for( int i = 0; i < comm_lines.size(); i++ )
  258.   outputStream.writeBytes( comm_lines.elementAt(i) + "n" );
  259.     
  260. outputStream.writeBytes( dateFormat.format( time1stamp ) + "n" + 
  261.  dateFormat.format( time2stamp ) + "n" );
  262. s.close();
  263.       }
  264.     } catch (StringIndexOutOfBoundsException e) { 
  265.       // i got it once in JDBC driver
  266.       parent_thread.debug_forced( "!" + e.toString() );
  267.     }
  268.     outputStream.writeBytes( "<-n" );
  269.   }
  270.   /** list mov files. We may have several push servers to store the same movie
  271.       - in this case the client should decide himself what push server is 
  272.       the nearest and is best to play this movie 
  273.   */
  274.   protected void listmovfiles_impl( Vector args, BufferedReader inputReader, 
  275.     DataOutputStream outputStream,
  276.     boolean SuperuserStatus ) 
  277.     throws SyntaxException, SQLException, IOException {
  278.     if( dbConnection == null ) 
  279.       {
  280. parent_thread.debug_forced("!Not connectedn");
  281. outputStream.writeBytes( "->n" + _disconnect_[KEY] + "n<-n" );
  282. return;
  283.       }
  284.     
  285.     // second argument must be 'id'
  286.     if( args.size() != 2 ) 
  287.       throw new SyntaxException( _list_mov_files_[KEY] + 
  288.  " command accepts exactly" +
  289.  " 1 parameter - integer ID of movie" );
  290.     int id = Integer.parseInt( (String)args.elementAt(1) );
  291.     Statement s;
  292.     ResultSet rs;
  293.     s = dbConnection.createStatement();
  294.     rs = s.executeQuery
  295.       ("select mpegfile, pushserv_id, starttm, stoptm " + 
  296.        "from moviefiles f where f.id = " + id);
  297.     outputStream.writeBytes( "->n" );
  298.     while( rs.next() ) {
  299.       String mpegf = rs.getString( "mpegfile" );
  300.       String pushserv_id = rs.getString( "pushserv_id" );
  301.       // the client is not interested what id this push server have
  302.       // client wants IP address and port number
  303.       String ip_addr = props.getProperty
  304. ( props.PushServN_IP + pushserv_id );
  305.       String control_port = props.getProperty
  306. ( props.PushServN_Control + pushserv_id );
  307.       String base = props.getProperty( props.PushServN_PPrefix + pushserv_id );
  308.       mpegf = base + "/" + mpegf;
  309.       Date start = rs.getTimestamp( "starttm" );
  310.       Date stop = rs.getTimestamp( "stoptm" );
  311.       if( stop == null )
  312. {
  313.   application.log( 0, "unfinished file in movie #" + 
  314.    String.valueOf( id ));
  315.   stop = Calendar.getInstance().getTime();
  316. }
  317.       outputStream.writeBytes( mpegf + "n" + pushserv_id + "n" +
  318.        ip_addr + "n" + control_port + "n" +
  319.        dateFormat.format( start ) + 
  320.        "n" + dateFormat.format( stop ) + "n" );
  321.     }
  322.     outputStream.writeBytes( "<-n" );
  323.     s.close();
  324.   }
  325.   
  326.   /* list captions. specify id and optionally listing type
  327.    */
  328.   protected void list_captions( Vector args, BufferedReader inputReader, 
  329.       DataOutputStream outputStream,
  330.       boolean SuperuserStatus ) 
  331.     throws SyntaxException, SQLException, IOException {
  332.     if( dbConnection == null ) 
  333.       {
  334. parent_thread.debug_forced("!Not connectedn");
  335. outputStream.writeBytes( "->n" + _disconnect_[KEY] + "n<-n" );
  336. return;
  337.       }
  338.     
  339.     if( args.size() < 2 ) 
  340.       throw new SyntaxException( _list_captions_[KEY] + " " + 
  341.  _list_captions_[SHDESC] );
  342.     int id;
  343.     try {
  344.       id = Integer.parseInt( (String)args.elementAt(1) );
  345.     } catch ( NumberFormatException e ) {
  346.       throw new SyntaxException( _list_captions_[KEY] + " " + 
  347.  _list_captions_[SHDESC] +" "+e.toString());
  348.     }
  349.     Statement s;
  350.     ResultSet rs;
  351.     s = dbConnection.createStatement();
  352.     rs = s.executeQuery
  353.       ("select text, captime from captions c where c.id = "+id);
  354.     outputStream.writeBytes( "->n" );
  355.     while( rs.next() ) {
  356.       String cap = rs.getString( "text" );
  357.       java.util.Date time = rs.getTimestamp( "captime" );
  358.       outputStream.writeBytes( cap + "n" + dateFormat.format( time )+"n");
  359.     }
  360.     outputStream.writeBytes( "<-n" );
  361.     s.close();
  362.   }
  363.   /* add new movie to database. Returns automatically generated ID.
  364.      stopTime may be null - we may not know the time when movie will ends
  365.    */
  366.   protected int add_new_movie( String movieName, Calendar startTime, 
  367.        Calendar stopTime ) 
  368.     throws SyntaxException, SQLException, IOException {
  369.     String start = dateFormat.format( startTime.getTime() );
  370.     String stop = null;
  371.     if( stopTime != null )
  372.       stop = dateFormat.format( stopTime.getTime() );
  373.     return add_new_movie( movieName, start, stop );
  374.   }
  375.   /* add new movie to database. Returns automatically generated ID.
  376.      stopTime may be null - we may not know the time when movie will ends
  377.    */
  378.   protected int add_new_movie( String movieName, String startTime, 
  379.        String stopTime ) 
  380.     throws SyntaxException, SQLException, IOException {
  381.     if( dbConnection == null ) 
  382.       {
  383. parent_thread.debug_forced("!Not connectedn");
  384. return 0;
  385.       }
  386.     Statement s = dbConnection.createStatement();
  387.     ResultSet rs;
  388.     // if exist - don't overwrite
  389.     try {
  390.       int i_postfix = 0;
  391.       // generate the unique name for the movie
  392.       while( true )
  393. {
  394.   String postfix = "";
  395.   if( i_postfix > 0 )
  396.     postfix = ", part " + String.valueOf( i_postfix );
  397.   rs = s.executeQuery
  398.     ("select title from movies m where m.title = '"
  399.      + movieName + postfix + "'" );
  400.   if( rs.next() ) // found
  401.     {
  402.       i_postfix = i_postfix + 1;
  403.       continue;
  404.     }
  405.   movieName = movieName + postfix;
  406.   break;
  407. }
  408.     } catch ( SQLException e ) {
  409.       parent_thread.debug( "movie doesn't exists" + e.toString() );
  410.     }
  411.     s.close();
  412.     s = dbConnection.createStatement();
  413.   
  414.     // search for a first free ID
  415.     int id = 1;
  416. //     for( id = 1; ; id++ ) {
  417. //       try {
  418. //  rs = s.executeQuery
  419. //    ( "select m.id from movies m where m.id = " + String.valueOf( id ));
  420. //       } catch ( SQLException e ) {
  421. //  break; // exit from loop, we just found new id
  422. //       }
  423. //       if( !rs.next() ) // found
  424. //  break;   
  425. //     }
  426.     try {
  427.       rs = s.executeQuery
  428. ( "select max( m.id ) + 1 as id from movies m" );
  429.       if( rs.next() ) 
  430. id = rs.getInt( "id" );
  431.     } catch ( SQLException e ) {
  432.       // that's ok
  433.       application.log( 3, e.toString() );
  434.     }
  435.     parent_thread.debug( "free id " + String.valueOf( id ) );
  436.     s.close();
  437.     s = dbConnection.createStatement();
  438.     if( stopTime != null )
  439.       s.executeUpdate
  440. ( "insert into movies (title, id, starttm, stoptm) values ('" + 
  441.   movieName + "'," + String.valueOf( id ) + ",'" +
  442.   startTime + "','" + stopTime +
  443.   "')" );
  444.     else
  445.       s.executeUpdate
  446. ( "insert into movies (title, id, starttm) values ('" + 
  447.   movieName + "'," + String.valueOf( id ) + ",'" +
  448.   startTime + "') " );
  449.     s.close();
  450.     return id;
  451.   }
  452.   
  453.   /** add files to movie. stop time may be null if we don't know when this 
  454.       movie file will ends
  455.    */
  456.   protected void add_movie_file( String mov_id, String pushserv_id, 
  457.  String mpegName, Calendar startTime, 
  458.  Calendar stopTime )
  459.     throws SyntaxException, SQLException, IOException {
  460.     String start = dateFormat.format( startTime.getTime() );
  461.     String stop = null;
  462.     if( stopTime != null )
  463.       stop = dateFormat.format( stopTime.getTime() );
  464.     add_movie_file( mov_id, pushserv_id, mpegName, start, stop );
  465.   }
  466.   /** add files to movie. stop time may be null if we don't know when this 
  467.       movie file will ends
  468.    */
  469.   protected void add_movie_file( String mov_id, String pushserv_id, 
  470.  String mpegName, String startTime, 
  471.  String stopTime )
  472.     throws SyntaxException, SQLException, IOException {
  473.     if( dbConnection == null ) 
  474.       {
  475. parent_thread.debug_forced("!Not connectedn");
  476. return;
  477.       }
  478.     Statement s = dbConnection.createStatement();
  479.     ResultSet rs;
  480.     // if exist - don't overwrite
  481.     try {
  482.       rs = s.executeQuery
  483. ( "select mpegfile from moviefiles m where m.id = " + mov_id + 
  484.   " and m.mpegfile = '" + mpegName + "'" );
  485.       if( rs.next() ) // found
  486. return;   
  487.     } catch ( SQLException e ) {
  488.       parent_thread.debug( "select mpegfile from moviefiles m where m.id = " + 
  489.    mov_id + " and m.mpegfile = '" + mpegName + "'" );
  490.       parent_thread.debug( "continue with " + e.toString() );
  491.     }
  492.   
  493.     // insert
  494.     if( stopTime != null )
  495.       s.executeUpdate
  496. ( "insert into moviefiles(id, pushserv_id, mpegfile, starttm, " + 
  497.   " stoptm)" +
  498.   " values (" + mov_id + ",'" + pushserv_id + "','" + 
  499.   mpegName + "','" + startTime + "','" + stopTime + "')" );
  500.     else
  501.       s.executeUpdate
  502. ( "insert into moviefiles (id, pushserv_id, mpegfile, starttm)" +
  503.   " values (" + mov_id + ",'" + pushserv_id + "','" + 
  504.   mpegName + "','" + startTime + "' )" );
  505.     s.close();
  506.   }
  507.   protected void mark_movie_stop_time( int movie_id )
  508.     throws SyntaxException, SQLException, IOException {
  509.     if( dbConnection == null ) 
  510.       {
  511. parent_thread.debug_forced("!Not connectedn");
  512. return;
  513.       }
  514.     // current time
  515.     String current_time = dateFormat.format(Calendar.getInstance().getTime());
  516.     Statement s = dbConnection.createStatement();
  517.     ResultSet rs;
  518.     // first set this time as stop for specified movie
  519.     s.executeUpdate
  520.       ( "update movies set stoptm = '" + current_time + "' where " +
  521. "id = " + String.valueOf( movie_id ) );
  522.     // second find the unfinished moviefile for that movie 
  523.     // Note: at that point the movie may have only a single moviefiles
  524.     // multiple moviefiles may be created only via 'append'
  525.     s.executeUpdate
  526.       ( "update moviefiles set stoptm = '" + current_time + "' where " +
  527. "id = " + String.valueOf( movie_id ) );
  528.   }
  529.   protected void add_caption( String id, String time, String text )
  530.     throws SyntaxException, SQLException, IOException {
  531.     if( dbConnection == null ) 
  532.       {
  533. parent_thread.debug_forced("!Not connectedn");
  534. return;
  535.       }
  536.     Statement s = dbConnection.createStatement();
  537.     ResultSet rs;
  538.     
  539.     // text may have chars, that must be quoted...
  540.     int idx = 0;
  541.     while( -1 != ( idx = text.indexOf( "'", idx ))) {
  542.       text = text.substring( 0, idx ) + "'" + text.substring( idx );
  543.       idx += 2;
  544.       if( idx >= text.length())
  545. break;
  546.     }
  547.       
  548.     // insert
  549.     s.executeUpdate
  550.       ( "insert into captions (id, text, captime) values (" + 
  551. id + ",'" + text + "','" + time + "')" );
  552.     s.close();
  553.   }
  554. }