2
* Entagged Audio Tag library
3
* Copyright (c) 2003-2005 Rapha�l Slinckx <raphael@slinckx.net>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
package org.jaudiotagger.audio.generic;
22
import java.io.IOException;
23
import java.io.RandomAccessFile;
24
import java.util.logging.Logger;
26
import org.jaudiotagger.audio.AudioFile;
27
import org.jaudiotagger.tag.Tag;
28
import org.jaudiotagger.audio.exceptions.CannotWriteException;
29
import org.jaudiotagger.audio.exceptions.ModifyVetoException;
30
import org.jaudiotagger.audio.exceptions.CannotReadException;
33
* This abstract class is the skeleton for tag writers.
35
* <p>It handles the creation/closing of the randomaccessfile objects and then call the subclass
36
* method writeTag or deleteTag. These two method have to be implemented in the
39
* @author Raphael Slinckx
40
* @version $Id: AudioFileWriter.java,v 1.6 2007/11/23 14:35:42 paultaylor Exp $
43
public abstract class AudioFileWriter
47
public static Logger logger = Logger.getLogger("org.jaudiotagger.audio.generic");
50
* If not <code>null</code>, this listener is used to notify the listener
51
* about modification events.<br>
53
private AudioFileModificationListener modificationListener = null;
56
* Delete the tag (if any) present in the given file
58
* @param f The file to process
59
* @throws CannotWriteException if anything went wrong
61
public synchronized void delete(AudioFile f) throws CannotReadException,CannotWriteException
63
if (!f.getFile().canWrite())
65
throw new CannotWriteException("Can't write to file \"" + f.getFile().getAbsolutePath() + "\"");
68
if (f.getFile().length() <= 150)
70
throw new CannotWriteException("Less than 150 byte \"" + f.getFile().getAbsolutePath() + "\"");
73
RandomAccessFile raf = null;
74
RandomAccessFile rafTemp = null;
76
// Will be set to true on VetoException, causing the finally block to
79
boolean revert = false;
83
tempF = File.createTempFile("entagged", ".tmp", f.getFile().getParentFile());
84
rafTemp = new RandomAccessFile(tempF, "rw");
85
raf = new RandomAccessFile(f.getFile(), "rw");
91
if (this.modificationListener != null)
93
this.modificationListener.fileWillBeModified(f, true);
95
deleteTag(raf, rafTemp);
96
if (this.modificationListener != null)
98
this.modificationListener.fileModified(f, tempF);
101
catch (ModifyVetoException veto)
103
throw new CannotWriteException(veto);
110
throw new CannotWriteException("\"" + f.getFile().getAbsolutePath() + "\" :" + e, e);
114
// will be set to the remaining file.
115
File result = f.getFile();
127
if (tempF.length() > 0 && !revert)
129
f.getFile().delete();
130
tempF.renameTo(f.getFile());
140
System.err.println("AudioFileWriter:113:\"" + f.getFile().getAbsolutePath() + "\" or \"" + tempF.getAbsolutePath() + "\" :" + ex);
143
if (this.modificationListener != null)
145
this.modificationListener.fileOperationFinished(result);
151
* Delete the tag (if any) present in the given randomaccessfile, and do not
152
* close it at the end.
154
* @param raf The source file, already opened in r-write mode
155
* @param tempRaf The temporary file opened in r-write mode
156
* @throws CannotWriteException if anything went wrong
158
public synchronized void delete(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException,CannotWriteException, IOException
162
deleteTag(raf, tempRaf);
166
* Same as above, but delete tag in the file.
168
* @throws IOException is thrown when the RandomAccessFile operations throw it
169
* (you should never throw them manually)
170
* @throws CannotWriteException when an error occured during the deletion of the tag
172
protected abstract void deleteTag(RandomAccessFile raf, RandomAccessFile tempRaf) throws CannotReadException,CannotWriteException, IOException;
175
* This method sets the {@link AudioFileModificationListener}.<br>
176
* There is only one listener allowed, if you want more instances to be
177
* supported, use the {@link ModificationHandler} to broadcast those events.<br>
179
* @param listener The listener. <code>null</code> allowed to deregister.
181
public synchronized void setAudioFileModificationListener(AudioFileModificationListener listener)
183
this.modificationListener = listener;
187
* Write the tag (if not empty) present in the AudioFile in the associated
190
* @param af The file we want to process
191
* @throws CannotWriteException if anything went wrong
193
public synchronized void write(AudioFile af) throws CannotWriteException
195
logger.info("Started writing tag data for file:"+af.getFile().getName());
197
// Preliminary checks
200
if (af.getTag().isEmpty())
206
catch(CannotReadException re)
208
throw new CannotWriteException("Can't write to file \"" + af.getFile().getAbsolutePath() + "\"");
211
if (!af.getFile().canWrite())
213
throw new CannotWriteException("Can't write to file \"" + af.getFile().getAbsolutePath() + "\"");
216
if (af.getFile().length() <= 150)
218
throw new CannotWriteException("Less than 150 byte \"" + af.getFile().getAbsolutePath() + "\"");
221
RandomAccessFile raf = null;
222
RandomAccessFile rafTemp = null;
225
// Will be set to true in exception block to not replace original file.
226
boolean cannotWrite = false;
229
//TODO Creates temp file in same folder as the original file, this is safe but would impose a performance
230
//overhead if the original file is on a networked drive
231
tempF = File.createTempFile("entagged", ".tmp", af.getFile().getParentFile());
232
rafTemp = new RandomAccessFile(tempF, "rw");
233
raf = new RandomAccessFile(af.getFile(), "rw");
238
if (this.modificationListener != null)
240
this.modificationListener.fileWillBeModified(af, false);
242
writeTag(af.getTag(), raf, rafTemp);
243
if (this.modificationListener != null)
245
this.modificationListener.fileModified(af, tempF);
248
catch (ModifyVetoException veto)
250
throw new CannotWriteException(veto);
255
e.printStackTrace(System.err);
257
throw new CannotWriteException("\"" + af.getFile().getAbsolutePath() + "\" :" + e.getMessage());
261
File result = af.getFile();
273
//If the tempoaray file was used and there were no problems replace original file with it
274
if (!cannotWrite && tempF.length() > 0)
276
af.getFile().delete();
277
tempF.renameTo(af.getFile());
280
//Either the original file was directly written to or the temp file was used but the write failed
281
//in either case delete the temp file.
289
System.err.println("AudioFileWriter:165:\"" + af.getFile().getAbsolutePath() + "\" or \"" + tempF.getAbsolutePath() + "\" :" + ex);
292
if (this.modificationListener != null)
294
this.modificationListener.fileOperationFinished(result);
300
* This is called when a tag has to be written in a file. Three parameters
301
* are provided, the tag to write (not empty) Two randomaccessfiles, the
302
* first points to the file where we want to write the given tag, and the
303
* second is an empty temporary file that can be used if e.g. the file has
304
* to be bigger than the original.
306
* If something has been written in the temporary file, when this method
307
* returns, the original file is deleted, and the temporary file is renamed
308
* the the original name
310
* If nothing has been written to it, it is simply deleted.
312
* This method can assume the raf, rafTemp are pointing to the first byte of
313
* the file. The subclass must not close these two files when the method
316
* @throws IOException is thrown when the RandomAccessFile operations throw it
317
* (you should never throw them manually)
318
* @throws CannotWriteException when an error occured during the generation of the tag
320
protected abstract void writeTag(Tag tag, RandomAccessFile raf, RandomAccessFile rafTemp) throws CannotReadException,CannotWriteException, IOException;