Index: jsword/src/test/java/org/crosswire/jsword/book/sword/SwordBookMetaDataTest.java =================================================================== --- jsword/src/test/java/org/crosswire/jsword/book/sword/SwordBookMetaDataTest.java Fri Oct 16 09:42:02 BST 2009 +++ jsword/src/test/java/org/crosswire/jsword/book/sword/SwordBookMetaDataTest.java Fri Oct 16 09:42:02 BST 2009 @@ -0,0 +1,51 @@ +package org.crosswire.jsword.book.sword; + +import junit.framework.TestCase; +import org.crosswire.jsword.book.BookDriver; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +/** + * Created by IntelliJ IDEA. + * User: mbergmann + * Date: 16.10.2009 + * Time: 09:18:57 + */ + +public class SwordBookMetaDataTest extends TestCase { + + File configFile = new File("testconfig.conf"); + SwordBookMetaData swordBookMetaData = null; + + + @Override + protected void setUp() throws Exception { + ConfigEntryTable table = new ConfigEntryTable("TestBook"); + table.add(ConfigEntryType.LANG, "de"); + table.add(ConfigEntryType.INITIALS, "TestBook"); + table.add(ConfigEntryType.DESCRIPTION, "MyNewBook"); + table.add(ConfigEntryType.MOD_DRV, "RawFiles"); + try { + table.save(configFile); + } catch(IOException e) { + System.out.println(e.getMessage()); + } + + swordBookMetaData = new SwordBookMetaData(configFile, "TestBook", new URI("")); + } + + @Override + protected void tearDown() throws Exception { + configFile.delete(); + } + + public void testPropertiesAccessors() { + assertNotNull(swordBookMetaData); + assertEquals(swordBookMetaData.getName(), "MyNewBook"); + assertEquals(swordBookMetaData.getInitials(), "TestBook"); + assertNotNull(swordBookMetaData.getLanguage()); + assertEquals(swordBookMetaData.getLanguage().getCode(), "de"); + } +} Index: jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java =================================================================== --- jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java (revision 1907) +++ jsword/src/main/java/org/crosswire/jsword/book/sword/RawBackend.java Thu Oct 22 10:46:36 BST 2009 @@ -17,14 +17,11 @@ * Copyright: 2005 * The copyright to this program is held by it's authors. * - * ID: $Id: RawBackend.java 1907 2008-07-25 19:00:13Z dmsmith $ + * ID: $Id$ */ package org.crosswire.jsword.book.sword; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.RandomAccessFile; +import java.io.*; import java.net.URI; import org.crosswire.common.activate.Activator; @@ -37,6 +34,7 @@ import org.crosswire.jsword.passage.Key; import org.crosswire.jsword.passage.KeyUtil; import org.crosswire.jsword.passage.Verse; +import org.crosswire.jsword.versification.BibleInfo; /** * Both Books and Commentaries seem to use the same format so this class @@ -100,7 +98,6 @@ checkActive(); Verse verse = KeyUtil.getVerse(key); - try { int testament = SwordConstants.getTestament(verse); @@ -120,13 +117,17 @@ } } + @Override + public void setRawText(Key key, String text) throws BookException, IOException { + } + /* (non-Javadoc) - * @see org.crosswire.jsword.book.sword.AbstractBackend#isWritable() - */ + * @see org.crosswire.jsword.book.sword.AbstractBackend#isWritable() + */ public boolean isWritable() { // For the module to be writable either the old testament or the new testament needs to be present - // (i.e. readable) and both the index and the data files need to be readable + // (i.e. readable) and both the index and the data files need to be writable if (idxFile[SwordConstants.TESTAMENT_OLD].canRead() && (idxFile[SwordConstants.TESTAMENT_OLD].canWrite() || !txtFile[SwordConstants.TESTAMENT_OLD].canWrite())) { @@ -140,13 +141,8 @@ return idxFile[SwordConstants.TESTAMENT_OLD].canRead() || idxFile[SwordConstants.TESTAMENT_NEW].canRead(); } - public void create(String path) - { - idxFile[SwordConstants.TESTAMENT_OLD] = new File(path + File.separator + SwordConstants.FILE_OT + SwordConstants.EXTENSION_VSS); - txtFile[SwordConstants.TESTAMENT_OLD] = new File(path + File.separator + SwordConstants.FILE_OT); - - idxFile[SwordConstants.TESTAMENT_NEW] = new File(path + File.separator + SwordConstants.FILE_NT + SwordConstants.EXTENSION_VSS); - txtFile[SwordConstants.TESTAMENT_NEW] = new File(path + File.separator + SwordConstants.FILE_NT); + public void create() throws IOException, BookException { + super.create(); } /* (non-Javadoc) @@ -154,7 +150,6 @@ */ public final void activate(Lock lock) { - URI path = null; try { @@ -262,9 +257,9 @@ * Get the Index (that is offset and size) for an entry. * @param entry * @return the index for the entry - * @throws IOException + * @throws IOException */ - private DataIndex getIndex(RandomAccessFile raf, long entry) throws IOException + protected DataIndex getIndex(RandomAccessFile raf, long entry) throws IOException { // Read the offset and size for this key from the index byte[] buffer = SwordUtil.readRAF(raf, entry * entrysize, entrysize); @@ -293,10 +288,12 @@ * Get the text for an indexed entry in the book. * * @param index the entry to get + * @param name name of the entry + * @param testament testament number 0, 1 or 2 * @return the text for the entry. - * @throws IOException + * @throws IOException on a IO problem */ - private String getEntry(String name, int testament, long index) throws IOException + protected String getEntry(String name, int testament, long index) throws IOException { DataIndex dataIndex = getIndex(idxRaf[testament], index); @@ -322,45 +319,30 @@ /** * Are we active */ - private boolean active; + protected boolean active; /** * How many bytes in the size count in the index */ - private int datasize; + protected int datasize; /** * The number of bytes for each entry in the index: either 6 or 8 */ - private int entrysize; + protected int entrysize; /** * The log stream */ private static final Logger log = Logger.getLogger(RawBackend.class); - /** - * The array of index files - */ - private RandomAccessFile[] idxRaf = new RandomAccessFile[3]; + protected RandomAccessFile[] idxRaf = new RandomAccessFile[3]; + protected RandomAccessFile[] txtRaf = new RandomAccessFile[3]; + protected File[] idxFile = new File[3]; + protected File[] txtFile = new File[3]; /** - * The array of data files - */ - private RandomAccessFile[] txtRaf = new RandomAccessFile[3]; - - /** - * The array of index random access files - */ - private File[] idxFile = new File[3]; - - /** - * The array of data random access files - */ - private File[] txtFile = new File[3]; - - /** * How many bytes in the offset pointers in the index */ - private static final int OFFSETSIZE = 4; + protected static final int OFFSETSIZE = 4; } Index: jsword/src/test/java/org/crosswire/jsword/book/sword/RawFileBackendTest.java =================================================================== --- jsword/src/test/java/org/crosswire/jsword/book/sword/RawFileBackendTest.java Thu Oct 22 22:53:55 BST 2009 +++ jsword/src/test/java/org/crosswire/jsword/book/sword/RawFileBackendTest.java Thu Oct 22 22:53:55 BST 2009 @@ -0,0 +1,82 @@ +package org.crosswire.jsword.book.sword; + +import junit.framework.TestCase; +import org.crosswire.jsword.book.BookException; +import org.crosswire.jsword.passage.Key; +import org.crosswire.jsword.passage.NoSuchVerseException; +import org.crosswire.jsword.passage.Passage; +import org.crosswire.jsword.passage.Verse; + +import java.io.File; +import java.io.IOException; +import java.net.URI; + +/** + * Created by IntelliJ IDEA. + * User: mbergmann + * Date: 16.10.2009 + * Time: 09:55:18 + */ + +public class RawFileBackendTest extends TestCase { + + final String modName = "TestComment"; + File configFile = new File("testconfig.conf"); + RawFileBackend backend = null; + + @Override + protected void setUp() throws Exception { + ConfigEntryTable table = new ConfigEntryTable(modName); + table.add(ConfigEntryType.LANG, "de"); + table.add(ConfigEntryType.INITIALS, modName); + table.add(ConfigEntryType.DESCRIPTION, "MyNewBook"); + table.add(ConfigEntryType.MOD_DRV, "RawFiles"); + table.add(ConfigEntryType.DATA_PATH, "test"); + try { + table.save(configFile); + } catch(IOException e) { + System.out.println(e.getMessage()); + } + + SwordBookMetaData swordBookMetaData = new SwordBookMetaData(configFile, modName, new URI("file:///tmp")); + backend = new RawFileBackend(swordBookMetaData, 2); + } + + @Override + protected void tearDown() throws Exception { + //configFile.delete(); + } + + public void testCreate() throws IOException, BookException { + backend.create(); + } + + public void testSetRawText() throws NoSuchVerseException, IOException, BookException { + Verse otVerse = new Verse(1,3,1); + Verse otVerse2 = new Verse(3,3,5); + Verse otVerse3 = new Verse(2,6,4); + Verse otVerse4 = new Verse(7,3,1); + Verse ntVerse = new Verse(61,1,2); + Verse ntVerse2 = new Verse(60,1,2); + Verse ntVerse3 = new Verse(66,22,21); + Verse ntVerse4 = new Verse(64,1,2); + + backend.setRawText(otVerse, "Hello OT"); + backend.setRawText(otVerse2, "Hello OT2"); + backend.setRawText(otVerse3, "Hello OT3"); + backend.setRawText(otVerse4, "Hello OT4"); + backend.setRawText(ntVerse, "Hello NT"); + backend.setRawText(ntVerse2, "Hello NT2"); + backend.setRawText(ntVerse3, "Hello NT3"); + backend.setRawText(ntVerse4, "Hello NT4"); + + assertEquals(backend.getRawText(otVerse), "Hello OT"); + assertEquals(backend.getRawText(otVerse2), "Hello OT2"); + assertEquals(backend.getRawText(otVerse3), "Hello OT3"); + assertEquals(backend.getRawText(otVerse4), "Hello OT4"); + assertEquals(backend.getRawText(ntVerse), "Hello NT"); + assertEquals(backend.getRawText(ntVerse2), "Hello NT2"); + assertEquals(backend.getRawText(ntVerse3), "Hello NT3"); + assertEquals(backend.getRawText(ntVerse4), "Hello NT4"); + } +} Index: jsword/src/main/java/org/crosswire/jsword/book/sword/ConfigEntryTable.java =================================================================== --- jsword/src/main/java/org/crosswire/jsword/book/sword/ConfigEntryTable.java (revision 1928) +++ jsword/src/main/java/org/crosswire/jsword/book/sword/ConfigEntryTable.java Thu Oct 15 08:54:30 BST 2009 @@ -17,7 +17,7 @@ * Copyright: 2005 * The copyright to this program is held by it's authors. * - * ID: $Id: ConfigEntryTable.java 1928 2009-02-22 17:57:49Z dmsmith $ + * ID: $Id$ */ package org.crosswire.jsword.book.sword; @@ -347,6 +347,12 @@ } } + public void save(File file) throws IOException + { + this.configFile = file; + this.save(); + } + private void loadContents(BufferedReader in) throws IOException { StringBuffer buf = new StringBuffer(); Index: jsword/src/main/java/org/crosswire/jsword/book/sword/RawFileBackend.java =================================================================== --- jsword/src/main/java/org/crosswire/jsword/book/sword/RawFileBackend.java Fri Oct 23 08:16:36 BST 2009 +++ jsword/src/main/java/org/crosswire/jsword/book/sword/RawFileBackend.java Fri Oct 23 08:16:36 BST 2009 @@ -0,0 +1,321 @@ +package org.crosswire.jsword.book.sword; + +import org.crosswire.common.util.Logger; +import org.crosswire.jsword.book.BookException; +import org.crosswire.jsword.passage.Key; +import org.crosswire.jsword.passage.KeyUtil; +import org.crosswire.jsword.passage.Verse; +import org.crosswire.jsword.versification.BibleInfo; + +import java.io.*; + +/** + * Created by IntelliJ IDEA. + * User: mbergmann + * Date: 14.10.2009 + * Time: 08:35:50 + */ + +public class RawFileBackend extends RawBackend { + + private static final Logger log = Logger.getLogger(RawFileBackend.class); + + private File incfile = null; + private int incfileValue = 0; + + public RawFileBackend(SwordBookMetaData sbmd, int datasize) { + super(sbmd, datasize); + + initIncFile(); + try { + incfileValue = readIncfile(); + } catch(IOException e) { + log.error("Error on reading incfile!"); + } + } + + private void initIncFile() { + try { + File tempIncfile = new File(getExpandedDataPath().getPath() + File.separator + "incfile"); + if(tempIncfile.exists()) { + this.incfile = tempIncfile; + } + } catch(BookException e) { + log.error("Error on checking incfile: " + e.getMessage()); + } + } + + @Override + public String getRawText(Key key) throws BookException { + return super.getRawText(key); + } + + /** + * Get the text for an indexed entry in the book. + * @param name name of the entry + * @param testament testament number 1 or 2 + * @param index the entry to get + * @return the text for the entry. + * @throws java.io.IOException on file error + */ + @Override + protected String getEntry(String name, int testament, long index) throws IOException { + + DataIndex dataIndex = getIndex(idxRaf[testament], index); + int size = dataIndex.getSize(); + if (size == 0) { + return ""; + } + + if (size < 0) { + log.error("In " + getBookMetaData().getInitials() + ": Verse " + name + " has a bad index size of " + size); + return ""; + } + + try { + File dataFile = getDataTextFile(testament, dataIndex); + byte[] textBytes = readTextDataFile(dataFile); + decipher(textBytes); + return SwordUtil.decode(name, textBytes, getBookMetaData().getBookCharset()); + } catch(BookException e) { + throw new IOException(e.getMessage()); + } + } + + @Override + public void setRawText(Key key, String text) throws BookException, IOException { + checkActive(); + + Verse verse = KeyUtil.getVerse(key); + int testament = SwordConstants.getTestament(verse); + long index = SwordConstants.getIndex(verse); + int oIndex = verse.getOrdinal() - 1; + + DataIndex dataIndex = getIndex(idxRaf[testament], index); + File dataFile; + if(dataIndex.getSize() == 0) { + dataFile = createDataTextFile(oIndex); + updateIndexFile(testament, index); + updateDataFile(testament, oIndex); + } else { + dataFile = getDataTextFile(testament, dataIndex); + } + + byte[] textData = text.getBytes("UTF-8"); + encipher(textData); + writeTextDataFile(dataFile, textData); + + if(oIndex >= this.incfileValue) { + this.incfileValue = oIndex+1; + writeIncfile(this.incfileValue); + } + } + + private File createDataTextFile(int index) throws BookException, IOException { + String dataPath = getExpandedDataPath().getPath(); + dataPath += File.separator + String.format("%07d", index); + File dataFile = new File(dataPath); + if(!dataFile.createNewFile()) { + log.info("Data file did already exist: " + dataPath); + } + return dataFile; + } + + private File getDataTextFile(int testament, DataIndex dataIndex) throws IOException, BookException { + File dataFile; + + // data size to be read from the data file (ot or nt) should be 9 bytes + // this will be the filename of the actual text file "\r\n" + byte[] data = SwordUtil.readRAF(txtRaf[testament], dataIndex.getOffset(), dataIndex.getSize()); + decipher(data); + if(data.length == 7) { + String dataFilename = new String(data, 0, 7); + String dataPath = getExpandedDataPath().getPath() + File.separator + dataFilename; + dataFile = new File(dataPath); + } else { + log.error("Read data is not of appropriate size of 9 bytes!"); + throw new IOException("Datalength is not 9 bytes!"); + } + return dataFile; + } + + protected void updateIndexFile(int testament, long index) throws IOException { + long indexFileWriteOffset = index * entrysize; + long dataFileStartPosition = txtRaf[testament].length(); + int dataFileLengthValue = 7; // filename is 7 bytes + 2 bytes for "\r\n" + byte[] startPositionData = littleEndian32BitByteArrayFromInt((int)dataFileStartPosition); + byte[] lengthValueData = littleEndian16BitByteArrayFromShort((short)dataFileLengthValue); + byte[] indexFileWriteData = new byte[6]; + + indexFileWriteData[0] = startPositionData[0]; + indexFileWriteData[1] = startPositionData[1]; + indexFileWriteData[2] = startPositionData[2]; + indexFileWriteData[3] = startPositionData[3]; + indexFileWriteData[4] = lengthValueData[0]; + indexFileWriteData[5] = lengthValueData[1]; + + SwordUtil.writeRAF( + idxRaf[testament], + indexFileWriteOffset, indexFileWriteData); + } + + protected void updateDataFile(int testament, long ordinal) throws IOException { + String fileName = String.format("%07d\r\n", ordinal); + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(txtFile[testament], true)); + bos.write(fileName.getBytes()); + bos.close(); + } + + @Override + public void create() throws IOException, BookException { + super.create(); + createDataFiles(); + createIndexFiles(); + createIncfile(); + + checkActive(); + + prepopulateIndexFiles(); + prepopulateIncfile(); + } + + @Override + public boolean isWritable() { + File otTextFile = txtFile[1]; + File ntTextFile = txtFile[2]; + File otIndexFile = idxFile[1]; + File ntIndexFile = idxFile[2]; + File incFile = this.incfile; + + if( + otTextFile.exists() && otTextFile.canRead() && otTextFile.canWrite() && + ntTextFile.exists() && ntTextFile.canRead() && ntTextFile.canWrite() && + otIndexFile.exists() && otIndexFile.canRead() && otIndexFile.canWrite() && + ntIndexFile.exists() && ntIndexFile.canRead() && ntIndexFile.canWrite() && + incFile.exists() && incFile.canRead() && incFile.canWrite()) { + return true; + } else { + return false; + } + } + + private void createDataFiles() throws IOException, BookException { + String path = getExpandedDataPath().getPath(); + + File otTextFile = new File(path + File.separator + SwordConstants.FILE_OT); + otTextFile.createNewFile(); + File ntTextFile = new File(path + File.separator + SwordConstants.FILE_NT); + ntTextFile.createNewFile(); + } + + private void createIndexFiles() throws IOException, BookException { + String path = getExpandedDataPath().getPath(); + + File otIndexFile = new File(path + File.separator + SwordConstants.FILE_OT + SwordConstants.EXTENSION_VSS); + otIndexFile.createNewFile(); + File ntIndexFile = new File(path + File.separator + SwordConstants.FILE_NT + SwordConstants.EXTENSION_VSS); + ntIndexFile.createNewFile(); + } + + private void prepopulateIndexFiles() throws IOException { + try { + File ntIndexFile = idxFile[SwordConstants.TESTAMENT_NEW]; + BufferedOutputStream ntIdxBos = new BufferedOutputStream(new FileOutputStream(ntIndexFile, false)); + + File otIndexFile = idxFile[SwordConstants.TESTAMENT_OLD]; + BufferedOutputStream otIdxBos = new BufferedOutputStream(new FileOutputStream(otIndexFile, false)); + + for(int i = 0;i < BibleInfo.versesInBible();i++) { + if((i+1) >= SwordConstants.ORDINAL_MAT11) { + writeInitialIndex(ntIdxBos); + } else { + writeInitialIndex(otIdxBos); + } + } + + ntIdxBos.close(); + otIdxBos.close(); + } catch(FileNotFoundException e) { + throw new IOException(e.getMessage()); + } + } + + private void createIncfile() throws IOException, BookException { + File tempIncfile = new File(getExpandedDataPath().getPath() + File.separator + "incfile"); + tempIncfile.createNewFile(); + this.incfile = tempIncfile; + } + + private void prepopulateIncfile() throws IOException { + writeIncfile(1); + } + + private void writeIncfile(int value) throws IOException { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(this.incfile, false); + fos.write(littleEndian32BitByteArrayFromInt(value)); + } catch(FileNotFoundException e) { + log.error("Error on writing to incfile, file should exist already!"); + log.error(e.getMessage()); + } finally { + fos.close(); + } + } + + private int readIncfile() throws IOException { + int ret = -1; + if(this.incfile != null) { + FileInputStream fis = null; + try { + fis = new FileInputStream(this.incfile); + byte[] buffer = new byte[4]; + fis.read(buffer); + ret = SwordUtil.decodeLittleEndian32(buffer, 0); + } catch(FileNotFoundException e) { + log.error("Error on writing to incfile, file should exist already!"); + log.error(e.getMessage()); + } finally { + fis.close(); + } + } + + return ret; + } + + private void writeInitialIndex(BufferedOutputStream outStream) throws IOException { + outStream.write(littleEndian32BitByteArrayFromInt(0)); // offset + outStream.write(littleEndian16BitByteArrayFromShort((short)0)); // length + } + + private byte[] readTextDataFile(File dataFile) throws IOException { + try { + byte[] textData = new byte[(int)dataFile.length()]; + BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(dataFile)); + inStream.read(textData); + inStream.close(); + return textData; + } catch(FileNotFoundException ex) { + log.error(ex.getMessage()); + throw new IOException("Could not read text data file, file not found: " + dataFile.getName()); + } + } + + private void writeTextDataFile(File dataFile, byte[] textData) throws IOException { + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dataFile, false)); + bos.write(textData); + bos.close(); + } + + private byte[] littleEndian32BitByteArrayFromInt(int val) { + byte[] buffer = new byte[4]; + SwordUtil.encodeLittleEndian32(val, buffer, 0); + return buffer; + } + + private byte[] littleEndian16BitByteArrayFromShort(short val) { + byte[] buffer = new byte[2]; + SwordUtil.encodeLittleEndian16(val, buffer, 0); + return buffer; + } +} Index: jsword/src/main/java/org/crosswire/jsword/book/sword/SwordUtil.java =================================================================== --- jsword/src/main/java/org/crosswire/jsword/book/sword/SwordUtil.java (revision 1887) +++ jsword/src/main/java/org/crosswire/jsword/book/sword/SwordUtil.java Thu Oct 22 10:27:46 BST 2009 @@ -50,6 +50,7 @@ * @param offset The start of the record to read * @param theSize The number of bytes to read * @return the read data + * @throws IOException on error */ protected static byte[] readRAF(RandomAccessFile raf, long offset, int theSize) throws IOException { @@ -63,6 +64,7 @@ * @param raf The file to read * @param theSize The number of bytes to read * @return the read data + * @throws IOException on error */ protected static byte[] readNextRAF(RandomAccessFile raf, int theSize) throws IOException { @@ -88,11 +90,31 @@ } /** + * Writes "data" to a RandomAccessFile at the "offset" position + * @param raf RandomAvccessFile + * @param offset offset to write at + * @param data data to write + * @throws IOException on error + */ + protected static void writeRAF(RandomAccessFile raf, long offset, byte[] data) throws IOException { + raf.seek(offset); + writeNextRAF(raf, data); + } + + protected static void writeNextRAF(RandomAccessFile raf, byte[] data) throws IOException { + if(data == null) { + return; + } + raf.write(data); + } + + /** * Read a RandomAccessFile until a particular byte is seen * @param raf The file to read * @param offset The start of the record to read * @param stopByte The point at which to stop reading * @return the read data + * @throws IOException on error */ protected static byte[] readUntilRAF(RandomAccessFile raf, int offset, byte stopByte) throws IOException { @@ -105,6 +127,7 @@ * @param raf The file to read * @param stopByte The point at which to stop reading * @return the read data + * @throws IOException on error */ protected static byte[] readUntilRAF(RandomAccessFile raf, byte stopByte) throws IOException { Index: jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java =================================================================== --- jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java (revision 1890) +++ jsword/src/main/java/org/crosswire/jsword/book/sword/AbstractBackend.java Wed Oct 21 08:49:08 BST 2009 @@ -17,10 +17,12 @@ * Copyright: 2005 * The copyright to this program is held by it's authors. * - * ID: $Id: AbstractBackend.java 1890 2008-07-09 12:15:15Z dmsmith $ + * ID: $Id$ */ package org.crosswire.jsword.book.sword; +import java.io.File; +import java.io.IOException; import java.net.URI; import org.crosswire.common.activate.Activatable; @@ -131,14 +133,23 @@ /** * Set the text allotted for the given verse - * @param key The key to fetch + * @param key The key to set text to + * @param text The text to be set for key * @throws BookException If the data can not be set. + * @throws IOException If the module data path could not be created. */ - public void setRawText(Key key, String text) /* throws BookException */ - { - throw new UnsupportedOperationException("Could not set text (" + text + ") for " + key); //$NON-NLS-1$ //$NON-NLS-2$ + public void setRawText(Key key, String text) throws BookException, IOException { } + public void create() throws IOException, BookException { + File dataPath = new File(getExpandedDataPath()); + if(!dataPath.exists()) { + if(!dataPath.mkdirs()) { + throw new IOException("Unable to create module data path!"); + } + } + } + /** * Returns whether this AbstractBackend is implemented. * @return true if this AbstractBackend is implemented. Index: jsword/src/test/java/org/crosswire/jsword/book/sword/ConfigEntryTableTest.java =================================================================== --- jsword/src/test/java/org/crosswire/jsword/book/sword/ConfigEntryTableTest.java Fri Oct 16 09:16:07 BST 2009 +++ jsword/src/test/java/org/crosswire/jsword/book/sword/ConfigEntryTableTest.java Fri Oct 16 09:16:07 BST 2009 @@ -0,0 +1,51 @@ +package org.crosswire.jsword.book.sword; + +import junit.framework.TestCase; +import org.crosswire.common.util.Language; + +import java.io.File; +import java.io.IOException; + +/** + * Created by IntelliJ IDEA. + * User: mbergmann + * Date: 15.10.2009 + * Time: 08:32:12 + */ + +public class ConfigEntryTableTest extends TestCase { + + public void testCreateConfigEntryTableInstance() { + ConfigEntryTable table = new ConfigEntryTable("TestBook"); + assertNotNull(table); + } + + public void testAddConfigEntry() { + ConfigEntryTable table = new ConfigEntryTable("TestBook"); + assertNotNull(table); + + table.add(ConfigEntryType.LANG, "de"); + assertEquals(table.getValue(ConfigEntryType.LANG), "de"); + } + + public void testSaveConfigEntryTable() { + ConfigEntryTable table = new ConfigEntryTable("TestBook"); + assertNotNull(table); + + table.add(ConfigEntryType.LANG, "de"); + Language lang = (Language)table.getValue(ConfigEntryType.LANG); + assertNotNull(lang); + assertEquals(lang.getCode(), "de"); + table.add(ConfigEntryType.INITIALS, "TestBook"); + assertEquals(table.getValue(ConfigEntryType.INITIALS), "TestBook"); + + File configFile = new File("testconfig.conf"); + try { + table.save(configFile); + } catch(IOException e) { + assertTrue(false); + } finally { + configFile.delete(); + } + } +}