Finished up the importer and fixed various things along the way.

git-svn-id: https://samskivert.googlecode.com/svn/trunk@101 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-03-18 06:58:55 +00:00
parent d9df144cbf
commit 69f51a8559
16 changed files with 689 additions and 149 deletions
+1
View File
@@ -0,0 +1 @@
extern
+1 -1
View File
@@ -52,7 +52,7 @@ if (defined $libpath) {
}
# put everything in our class path
my $classpath = "-classpath $jlib:$root/src/java";
my $classpath = "-classpath $jlib:$root/dist/classes";
# any zip or jar files in our lib/ directory get added to the class path
if (opendir(DIR, "$root/lib")) {
+59
View File
@@ -0,0 +1,59 @@
<!-- build configuration -->
<project name="robodj" default="compile" basedir=".">
<!-- configuration parameters -->
<property name="app.name" value="robodj"/>
<property name="deploy.home" value="dist"/>
<property name="dist.home" value="${deploy.home}"/>
<property name="dist.jar" value="${app.name}.jar"/>
<property name="javadoc.home" value="${deploy.home}/docs"/>
<property name="build.compiler" value="jikes"/>
<property name="java.libraries" value="/usr/share/java"/>
<!-- prepares the application directories -->
<target name="prepare">
<mkdir dir="${deploy.home}"/>
<mkdir dir="${deploy.home}/classes"/>
<mkdir dir="${javadoc.home}"/>
<!-- copy media into the target directory -->
<copy todir="${deploy.home}/classes">
<fileset dir="src/java" includes="**/*.gif"/>
<fileset dir="src/java" includes="**/*.jpg"/>
</copy>
</target>
<!-- cleans out the installed application -->
<target name="clean">
<delete dir="${deploy.home}"/>
</target>
<!-- build the java class files -->
<target name="compile" depends="prepare">
<javac srcdir="src/java" destdir="${deploy.home}/classes"
debug="on" optimize="off" deprecation="off">
<classpath>
<fileset dir="${java.libraries}" includes="**/*.jar"/>
<fileset dir="lib" includes="**/*.jar"/>
<pathelement location="${deploy.home}/classes"/>
</classpath>
</javac>
</target>
<!-- build the javadoc documentation -->
<target name="javadoc" depends="prepare">
<javadoc sourcepath="src/java"
packagenames="robodj.*"
classpath="${deploy.home}/classes"
destdir="${javadoc.home}"/>
</target>
<!-- the default target is to rebuild everything -->
<target name="all" depends="clean,prepare,compile,javadoc"/>
<!-- builds our distribution files (war and jar) -->
<target name="dist" depends="prepare,compile">
<jar jarfile="${dist.home}/${dist.jar}"
basedir="${deploy.home}/classes"/>
</target>
</project>
+7
View File
@@ -0,0 +1,7 @@
RoboDJ Notes
------------
- Catch database errors after the ripping process and allow use to retry
commit to database after fixing database unavailability.
- Impersonate a registered CDDB client until we can get "approval".
+1
View File
@@ -0,0 +1 @@
*.jar
+38
View File
@@ -0,0 +1,38 @@
//
// $Id: Log.java,v 1.1 2001/03/18 06:58:55 mdb Exp $
package robodj;
/**
* A placeholder class that contains a reference to the log object used by
* the robodj package.
*/
public class Log
{
public static com.samskivert.util.Log log =
new com.samskivert.util.Log("robodj");
/** Convenience function. */
public static void debug (String message)
{
log.debug(message);
}
/** Convenience function. */
public static void info (String message)
{
log.info(message);
}
/** Convenience function. */
public static void warning (String message)
{
log.warning(message);
}
/** Convenience function. */
public static void logStackTrace (Throwable t)
{
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
}
}
@@ -0,0 +1,33 @@
//
// $Id: EncodeTest.java,v 1.1 2001/03/18 06:58:55 mdb Exp $
package robodj.convert;
import com.samskivert.net.cddb.*;
public class EncodeTest
{
public static void main (String[] args)
{
if (args.length < 2) {
System.err.println("Usage: EncodeTest source.wav dest.mp3");
System.exit(-1);
}
try {
Encoder encoder = new LameEncoder();
ConversionProgressListener listener =
new ConversionProgressListener() {
public void updateProgress (int percentDone)
{
System.out.println("Percent done: " +
percentDone + "%");
}
};
encoder.encodeTrack(args[0], args[1], listener);
} catch (Exception e) {
System.err.println("Error: " + e);
}
}
}
@@ -0,0 +1,104 @@
//
// $Id: LameEncoder.java,v 1.1 2001/03/18 06:58:55 mdb Exp $
package robodj.convert;
import java.io.*;
import java.util.ArrayList;
import gnu.regexp.*;
/**
* An encoder implementation that uses LAME to do it's job.
*/
public class LameEncoder implements Encoder
{
public void encodeTrack (String source, String dest,
ConversionProgressListener listener)
throws ConvertException
{
StringBuffer cmd = new StringBuffer("lame");
cmd.append(" --nohist"); // we don't want histogram output
cmd.append(" -v"); // request variable bitrate encoding
cmd.append(" ").append(source); // add source file name
cmd.append(" ").append(dest); // add output file name
// we'll need this for later
RE regex;
try {
// a line of input looks like this
// 0/1273 ( 0%)| 0:00/ 0:00...
regex = new RE("^\\s*(\\d+)/(\\d+)\\s*\\(.*");
} catch (REException ree) {
throw new ConvertException("Can't compile regexp?! " + ree);
}
try {
// fork off a cdparanoia process to read the TOC
Runtime rt = Runtime.getRuntime();
Process ripproc = rt.exec(cmd.toString());
InputStream in = ripproc.getErrorStream();
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);
// read output from the subprocess
String out;
int lastReported = 0;
while ((out = din.readLine()) != null) {
// if they don't care about the output then neither do we
if (listener == null) {
continue;
}
// parse the output
REMatch match = regex.getMatch(out);
if (match != null) {
int offset = -1, total = -1;
try {
offset = Integer.parseInt(match.toString(1));
total = Integer.parseInt(match.toString(2));
} catch (NumberFormatException nfe) {
System.err.println("Malformed position info: " + out);
continue;
}
int pctDone = (100 * offset) / total;
if (pctDone - lastReported >= 1) {
listener.updateProgress(pctDone);
lastReported = pctDone;
}
} else {
// System.out.println("Couldn't match: " + out);
}
}
// check the return value of the process
try {
int retval = ripproc.waitFor();
if (retval != 0) {
// ship off the error output from cdparanoia
throw new ConvertException(
"Encoder failed: " + retval);
}
} catch (InterruptedException ie) {
// why we were interrupted I can only speculate, but we'll
// go ahead and freak out anyway
throw new ConvertException("Interrupted while waiting for " +
"encoder process to exit.");
}
// if everything was successful, report completion
if (lastReported < 100) {
listener.updateProgress(100);
}
} catch (IOException ioe) {
throw new ConvertException(
"Error communicating with encoder:\n" + ioe);
}
}
}
@@ -1,5 +1,5 @@
//
// $Id: RipTest.java,v 1.3 2001/02/06 08:18:00 mdb Exp $
// $Id: RipTest.java,v 1.4 2001/03/18 06:58:55 mdb Exp $
package robodj.convert;
@@ -24,6 +24,7 @@ public class RipTest
int length = RipUtil.computeDiscLength(info);
try {
System.out.println("connecting to: " + hostname);
String rsp = cddb.connect(hostname);
// set the timeout to 30 seconds
@@ -80,7 +81,7 @@ public class RipTest
} else {
// try the CDDB lookup
lookupCDDB("us.cddb.com", info);
lookupCDDB("ca.freedb.org", info);
// rip a track, for fun
int track = 2;
@@ -1,5 +1,5 @@
//
// $Id: CDDBLookupPanel.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
// $Id: CDDBLookupPanel.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
@@ -34,11 +34,24 @@ public class CDDBLookupPanel
cdlabel.setFont(new Font("Helvetica", Font.BOLD, 24));
add(cdlabel, GroupLayout.FIXED);
// on the right hand side we want a status display to let the user
// know how the CDDB lookup process is going
GroupLayout vgl = new VGroupLayout(GroupLayout.STRETCH);
vgl.setOffAxisPolicy(GroupLayout.STRETCH);
_spanel = new JPanel(vgl);
JLabel sl = new JLabel("Status", JLabel.LEFT);
_spanel.add(sl, GroupLayout.FIXED);
// create the "insert cd" text label for the right hand side
_infoText = new JTextArea("Reading CD information...");
_infoText.setLineWrap(true);
_infoText.setEditable(false);
add(_infoText);
// make something for it to scroll around in
_spanel.add(new JScrollPane(_infoText));
// add our panel to the main group
add(_spanel);
}
public void wasAddedToFrame (ImporterFrame frame)
@@ -82,7 +95,7 @@ public class CDDBLookupPanel
public Object invoke ()
throws Exception
{
return CDDBUtil.doCDDBLookup("us.cddb.com", info);
return CDDBUtil.doCDDBLookup("ca.freedb.org", info);
}
public boolean abort ()
@@ -97,7 +110,7 @@ public class CDDBLookupPanel
CDDB.Detail[] details = (CDDB.Detail[])result;
// replace the info text with the CD info editor
remove(_infoText);
remove(_spanel);
_infoEditor = new CDInfoEditor(details, _info.length);
add(_infoEditor);
@@ -179,6 +192,7 @@ public class CDDBLookupPanel
protected ImporterFrame _frame;
protected JButton _next;
protected JPanel _spanel;
protected JTextArea _infoText;
protected CDInfoEditor _infoEditor;
@@ -1,5 +1,5 @@
//
// $Id: CDInfoEditor.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
// $Id: CDInfoEditor.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
@@ -26,10 +26,11 @@ public class CDInfoEditor
JLabel selLabel = new JLabel("Select...");
// create a string array for our combo box
String[] names = new String[details.length];
String[] names = new String[details.length + 1];
for (int i = 0; i < details.length; i++) {
names[i] = details[i].title;
}
names[details.length] = "<blank>";
_selBox = new JComboBox(names);
selPanel.add(selLabel, GroupLayout.FIXED);
@@ -1,9 +1,15 @@
//
// $Id: Importer.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
// $Id: Importer.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
import java.sql.SQLException;
import java.util.Properties;
import com.samskivert.util.Log;
import com.samskivert.util.PropertiesUtil;
import robodj.repository.Repository;
/**
* The importer is the GUI-based application for ripping, encoding and
@@ -11,10 +17,40 @@ import com.samskivert.util.Log;
*/
public class Importer
{
/**
* This is the string we use for the source field of entries created
* by the importer.
*/
public static final String ENTRY_SOURCE = "CD";
public static Log log = new Log("importer");
public static Properties config;
public static Repository repository;
public static void main (String[] args)
{
// set up our configuration by hand for now
config = new Properties();
config.setProperty("repository.db.driver", "org.gjt.mm.mysql.Driver");
config.setProperty("repository.db.username", "www");
config.setProperty("repository.db.password", "Il0ve2PL@Y");
config.setProperty("repository.db.url",
"jdbc:mysql://depravity:3306/robodj");
config.setProperty("repository.basedir", "/export/robodj/repository");
// create an interface to the database repository
try {
Properties dbprops =
PropertiesUtil.getSubProperties(config, "repository.db");
repository = new Repository(dbprops);
} catch (SQLException sqe) {
System.err.println("Unable to establish communication " +
"with music database: " + sqe);
System.exit(-1);
}
ImporterFrame frame = new ImporterFrame();
InsertCDPanel panel = new InsertCDPanel();
frame.setPanel(panel);
@@ -1,5 +1,5 @@
//
// $Id: ImporterFrame.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
// $Id: ImporterFrame.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
@@ -24,7 +24,9 @@ public class ImporterFrame extends JFrame
_top.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
// create a container for our control buttons
_buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
GroupLayout bgl = new HGroupLayout(GroupLayout.NONE);
bgl.setJustification(GroupLayout.RIGHT);
_buttonPanel = new JPanel(bgl);
// stick it into the frame
_top.add(_buttonPanel, GroupLayout.FIXED);
@@ -51,7 +53,6 @@ public class ImporterFrame extends JFrame
// then stick the new panel in there
if (panel != null) {
_panel = panel;
_panel.setBackground(Color.yellow);
_top.add(_panel, 0);
// let the panel know that it was added
_panel.wasAddedToFrame(this);
@@ -1,8 +1,10 @@
//
// $Id: Panel.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
// $Id: Panel.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
import javax.swing.JPanel;
public class Panel extends JPanel
{
}
@@ -1,11 +1,12 @@
//
// $Id: RipPanel.java,v 1.1 2000/12/10 07:02:09 mdb Exp $
// $Id: RipPanel.java,v 1.2 2001/03/18 06:58:55 mdb Exp $
package robodj.importer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
@@ -16,6 +17,7 @@ import com.samskivert.swing.util.*;
import com.samskivert.swing.*;
import com.samskivert.util.StringUtil;
import robodj.Log;
import robodj.convert.*;
import robodj.repository.*;
@@ -30,39 +32,324 @@ public class RipPanel
setLayout(gl);
// create our label for the left hand side
JLabel cdlabel = new JLabel("Ripping", JLabel.CENTER);
JLabel cdlabel = new JLabel("Converting", JLabel.CENTER);
cdlabel.setFont(new Font("Helvetica", Font.BOLD, 24));
add(cdlabel, GroupLayout.FIXED);
// create a panel for the progress display
GroupLayout vgl = new VGroupLayout(GroupLayout.STRETCH);
vgl.setOffAxisPolicy(GroupLayout.STRETCH);
JPanel ppanel = new JPanel(vgl);
// create the overall progress indicator
JLabel opl = new JLabel("Overall progress", JLabel.LEFT);
ppanel.add(opl, GroupLayout.FIXED);
// overall progress assumes equal time spent ripping and encoding
// each track on the disc. not entirely accurate, but reasonable
// for giving a general idea of how far along we are
_oprogress = new JProgressBar(0, 200*info.length);
ppanel.add(_oprogress, GroupLayout.FIXED);
// create the task progress indicator
JLabel tpl = new JLabel("Track progress", JLabel.LEFT);
ppanel.add(tpl, GroupLayout.FIXED);
_progress = new JProgressBar(0, 100);
ppanel.add(_progress, GroupLayout.FIXED);
// create the status log
JLabel sl = new JLabel("Status", JLabel.LEFT);
ppanel.add(sl, GroupLayout.FIXED);
_statusLog = new JTextArea();
_statusLog.setLineWrap(true);
_statusLog.setEditable(false);
// make something for it to scroll around in
ppanel.add(new JScrollPane(_statusLog));
// add our panel to the main group
add(ppanel);
// save this stuff for later
_info = info;
_entry = entry;
}
protected void postAsyncStatus (final String status)
{
SwingUtilities.invokeLater(new Runnable() {
public void run ()
{
_statusLog.append(status + "\n");
}
});
}
protected void postAsyncProgress (final int overallComplete,
final int taskComplete)
{
SwingUtilities.invokeLater(new Runnable() {
public void run ()
{
// update our progress indicators
_oprogress.setValue(overallComplete);
_progress.setValue(taskComplete);
}
});
}
protected static String createTempPath (int trackno, String ext)
{
return "/tmp/track" + trackno + "." + ext;
}
/** Handles the ripping and encoding of the tracks. */
protected class RipperTask
implements Task, ConversionProgressListener
{
public RipperTask (Ripper.TrackInfo[] info)
{
_info = info;
}
public Object invoke ()
throws Exception
{
Ripper ripper = new CDParanoiaRipper();
Encoder encoder = new LameEncoder();
for (int i = 0; i < _info.length; i++) {
_track = i+1;
// rip the track
_encoding = false;
// it takes a second or so for the ripper to start
// reporting progress, so we clear out the progress
// indicator so that the 100% progress of the previous
// track doesn't look like it applies to this new track
// while we're spinning up
updateProgress(0);
postAsyncStatus("Ripping track " + _track + "...");
String tpath = createTempPath(_track, "wav");
ripper.ripTrack(_info, _track, tpath, this);
// then encode it
_encoding = true;
updateProgress(0);
postAsyncStatus("Encoding track " + _track + "...");
String dpath = createTempPath(_track, "mp3");
encoder.encodeTrack(tpath, dpath, this);
// remove the source wav file
File tfile = new File(tpath);
if (!tfile.delete()) {
postAsyncStatus("Unable to remove temp file " +
"for track " + _track + ".");
}
}
return null;
}
public boolean abort ()
{
// no abort presently
return false;
}
public void updateProgress (int percentComplete)
{
// first add completeness for tracks we've already done
int overallComplete = (_track-1) * 200;
// if we're encoding, then we finished ripping this track
if (_encoding) {
overallComplete += 100;
}
// finally add the percent complete for the current task
overallComplete += percentComplete;
// and pass it all on to the UI for display
postAsyncProgress(overallComplete, percentComplete);
}
protected Ripper.TrackInfo[] _info;
protected int _track;
protected boolean _encoding;
}
/** Commits the completed entry into the repository. */
protected class CommitterTask
implements Task
{
public CommitterTask (Entry entry, Ripper.TrackInfo[] info)
{
_entry = entry;
_info = info;
}
public Object invoke ()
throws Exception
{
int entryid = -1;
try {
// determine the target directory for the mp3 files
String rbase =
Importer.config.getProperty("repository.basedir");
if (StringUtil.blank(rbase)) {
throw new Exception("No mp3 repository directory " +
"specified.");
}
// ensure the repository directory exists
File rbf = new File(rbase);
if (!rbf.exists() || !rbf.isDirectory()) {
throw new Exception("Repository base directory '" +
rbase + "' is not valid.");
}
postAsyncStatus("Creating repository directory.");
// create the hash directory
int hcode = _entry.title.hashCode();
if (hcode < 0) {
hcode *= -1;
}
System.out.println(Integer.toHexString(255 % 0xFF));
String hash = Integer.toHexString(hcode % 0xFF);
StringBuffer tpath = new StringBuffer(rbase);
if (tpath.charAt(tpath.length()-1) != '/') {
tpath.append("/");
}
tpath.append(hash);
File tdir = new File(tpath.toString());
if (!tdir.exists()) {
if (!tdir.mkdir()) {
throw new Exception("Unable to create target " +
"directory: " + tpath);
}
} else {
// make sure it's a directory
if (!tdir.isDirectory()) {
throw new Exception("Target directory '" + tpath +
"' is not valid.");
}
}
// fill in the entry source since we ripped this from CD
_entry.source = Importer.ENTRY_SOURCE;
// fill in blanks for the locations of the tunes because
// we won't know the name of the directory until we are
// assigned an entry id
for (int i = 0; i < _entry.songs.length; i++) {
_entry.songs[i].location = "";
}
postAsyncStatus("Creating database entry.");
// insert the entry into the repository so that we get the
// proper entry id which we'll need to put the tracks in their
// proper place in the repository
Importer.repository.insertEntry(_entry);
// track this so that we can clean up in case of failure
entryid = _entry.entryid;
// now that we have an entry id, fully construct the
// target path
tpath.append("/").append(_entry.entryid);
tdir = new File(tpath.toString());
if (!tdir.mkdir()) {
throw new Exception("Unable to create target " +
"directory: " + tpath);
}
postAsyncStatus("Moving tracks into repository directory.");
// move the tracks into the target directory
tpath.append("/");
for (int i = 0; i < _entry.songs.length; i++) {
int tno = i+1;
// figure out the necessary paths
String npath = tpath.toString() + tno + ".mp3";
String opath = createTempPath(tno, "mp3");
// move the file
File ofile = new File(opath);
File nfile = new File(npath);
if (!ofile.renameTo(nfile)) {
throw new Exception("Unable to move track " + tno +
" to target location: " + npath);
}
// and update the song object
_entry.songs[i].location = npath;
}
// finally update the entry in the database
Importer.repository.updateEntry(_entry);
// and clear out the entryid to indicate success
entryid = -1;
postAsyncStatus("Import complete.");
return null;
} finally {
// if we got halfway through creating our entry, remove it
// from the database
if (entryid != -1) {
Importer.repository.deleteEntry(_entry);
}
}
}
public boolean abort ()
{
// we don't support aborting. this shouldn't take long at all
return false;
}
protected Entry _entry;
protected Ripper.TrackInfo[] _info;
}
public void wasAddedToFrame (ImporterFrame frame)
{
// keep this for later
_frame = frame;
frame.addControlButton("Cancel", "cancel", this);
// add our next and cancel buttons
_cancel = frame.addControlButton("Cancel", "cancel", this);
_next = frame.addControlButton("Next...", "next", this);
_next.setEnabled(false);
// create our info task and set it a running
Task ripTask = new RipperTask(_info);
TaskMaster.invokeTask("convert", ripTask, this);
}
public void taskCompleted (String name, Object result)
{
if (name.equals("getinfo")) {
if (name.equals("convert")) {
// yay! we're all done. commit the entry to the repository
Task commitTask = new CommitterTask(_entry, _info);
TaskMaster.invokeTask("commit", commitTask, this);
} else if (name.equals("cddb_lookup")) {
} else if (name.equals("commit")) {
// we're all done. fix up the buttons and call it good
_cancel.setEnabled(false);
_next.setLabel("Exit");
_next.setEnabled(true);
}
}
public void taskFailed (String name, Throwable exception)
{
if (name.equals("getinfo")) {
} else if (name.equals("cddb_lookup")) {
}
String msg;
if (Exception.class.equals(exception.getClass())) {
msg = exception.getMessage();
} else {
msg = exception.toString();
}
_statusLog.append("Error: " + msg + "\n");
Log.logStackTrace(exception);
}
public void actionPerformed (ActionEvent e)
@@ -72,6 +359,7 @@ public class RipPanel
System.exit(0);
} else if (cmd.equals("next")) {
System.exit(0);
} else {
System.out.println("Unknown action event: " + cmd);
@@ -80,6 +368,12 @@ public class RipPanel
protected ImporterFrame _frame;
protected JButton _next;
protected JButton _cancel;
protected JLabel _actionLabel;
protected JProgressBar _oprogress;
protected JProgressBar _progress;
protected JTextArea _statusLog;
protected Ripper.TrackInfo[] _info;
protected Entry _entry;
@@ -1,5 +1,5 @@
//
// $Id: Repository.java,v 1.2 2001/02/13 05:48:29 mdb Exp $
// $Id: Repository.java,v 1.3 2001/03/18 06:58:55 mdb Exp $
package robodj.repository;
@@ -91,39 +91,30 @@ public class Repository extends MySQLRepository
* and the song objects) will be filled in with the entryid of the
* newly created entry.
*/
public void insertEntry (Entry entry)
public void insertEntry (final Entry entry)
throws SQLException
{
try {
// insert the entry into the entry table
_etable.insert(entry);
execute(new Operation () {
public void invoke () throws SQLException
{
// insert the entry into the entry table
_etable.insert(entry);
// update the entryid now that it's known
entry.entryid = lastInsertedId();
// update the entryid now that it's known
entry.entryid = lastInsertedId();
// and insert all of it's songs into the songs table
if (entry.songs != null) {
for (int i = 0; i < entry.songs.length; i++) {
// insert the proper entryid
entry.songs[i].entryid = entry.entryid;
_stable.insert(entry.songs[i]);
// find out what songid was assigned
entry.songs[i].songid = lastInsertedId();
}
}
_session.commit();
} catch (SQLException sqe) {
// back out our changes if something got hosed
_session.rollback();
throw sqe;
} catch (RuntimeException rte) {
// back out our changes if something got hosed
_session.rollback();
throw rte;
}
// and insert all of it's songs into the songs table
if (entry.songs != null) {
for (int i = 0; i < entry.songs.length; i++) {
// insert the proper entryid
entry.songs[i].entryid = entry.entryid;
_stable.insert(entry.songs[i]);
// find out what songid was assigned
entry.songs[i].songid = lastInsertedId();
}
}
}
});
}
/**
@@ -136,57 +127,40 @@ public class Repository extends MySQLRepository
* @see addSongToEntry
* @see removeSongFromEntry
*/
public void updateEntry (Entry entry)
public void updateEntry (final Entry entry)
throws SQLException
{
try {
// update the entry
_etable.update(entry);
execute(new Operation () {
public void invoke () throws SQLException
{
// update the entry
_etable.update(entry);
// and the entry's songs
if (entry.songs != null) {
for (int i = 0; i < entry.songs.length; i++) {
_stable.update(entry.songs[i]);
}
}
_session.commit();
} catch (SQLException sqe) {
// back out our changes if something got hosed
_session.rollback();
throw sqe;
} catch (RuntimeException rte) {
// back out our changes if something got hosed
_session.rollback();
throw rte;
}
// and the entry's songs
if (entry.songs != null) {
for (int i = 0; i < entry.songs.length; i++) {
_stable.update(entry.songs[i]);
}
}
}
});
}
/**
* Removes the entry (and all associated songs) from the database.
*/
public void deleteEntry (Entry entry)
public void deleteEntry (final Entry entry)
throws SQLException
{
try {
// remove the entry from the entry table and the foreign key
// constraints will automatically remove all of the
// corresponding songs
_etable.delete(entry);
_session.commit();
} catch (SQLException sqe) {
// back out our changes if something got hosed
_session.rollback();
throw sqe;
} catch (RuntimeException rte) {
// back out our changes if something got hosed
_session.rollback();
throw rte;
}
execute(new Operation () {
public void invoke () throws SQLException
{
// remove the entry from the entry table and the foreign
// key constraints will automatically remove all of the
// corresponding songs
_etable.delete(entry);
}
});
}
/**
@@ -201,81 +175,55 @@ public class Repository extends MySQLRepository
*
* @see updateSong
*/
public void addSongToEntry (Entry entry, Song song)
public void addSongToEntry (final Entry entry, final Song song)
throws SQLException
{
try {
// fill in the appropriate entry id value
song.entryid = entry.entryid;
execute(new Operation () {
public void invoke () throws SQLException
{
// fill in the appropriate entry id value
song.entryid = entry.entryid;
// and stick the song into the database
_stable.insert(song);
// communicate the songid back to the caller
song.songid = lastInsertedId();
_session.commit();
} catch (SQLException sqe) {
// back out our changes if something got hosed
_session.rollback();
throw sqe;
} catch (RuntimeException rte) {
// back out our changes if something got hosed
_session.rollback();
throw rte;
}
// and stick the song into the database
_stable.insert(song);
// communicate the songid back to the caller
song.songid = lastInsertedId();
}
});
}
/**
* Updates the specified song individually. The songid and entryid
* parameters should already be set to the appropriate values.
*/
public void updateSong (Song song)
public void updateSong (final Song song)
throws SQLException
{
try {
_stable.update(song);
_session.commit();
} catch (SQLException sqe) {
// back out our changes if something got hosed
_session.rollback();
throw sqe;
} catch (RuntimeException rte) {
// back out our changes if something got hosed
_session.rollback();
throw rte;
}
execute(new Operation () {
public void invoke () throws SQLException
{
_stable.update(song);
}
});
}
/**
* Creates a category with the specified name and returns the id of
* that new category.
*/
public int createCategory (String name)
public int createCategory (final String name)
throws SQLException
{
try {
Category cat = new Category();
cat.name = name;
_ctable.insert(cat);
execute(new Operation () {
public void invoke () throws SQLException
{
Category cat = new Category();
cat.name = name;
_ctable.insert(cat);
}
});
int categoryid = lastInsertedId();
_session.commit();
return categoryid;
} catch (SQLException sqe) {
// back out our changes if something got hosed
_session.rollback();
throw sqe;
} catch (RuntimeException rte) {
// back out our changes if something got hosed
_session.rollback();
throw rte;
}
return lastInsertedId();
}
/**