marytts.util.MaryCache Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2009 DFKI GmbH.
* All Rights Reserved. Use is subject to license terms.
*
* This file is part of MARY TTS.
*
* MARY TTS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
*/
package marytts.util;
import java.io.File;
import java.net.MalformedURLException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import marytts.server.MaryProperties;
/**
* @author marc
*
*/
public class MaryCache {
private static MaryCache maryCache;
/**
* Try to get the MaryCache object. This will either return the previously created MaryCache, or if none exists, it will try
* to create one.
*
* @see #haveCache if you just want to check if the cache exists.
*
* To the extent possible this method gives the no-throw guarantee: if the cache cannot be created, null will be returned
* and any exception will be logged.
* @return the MaryCache singleton object, or null if none could be created.
*/
public static MaryCache getCache() {
if (maryCache == null) {
try {
File targetFile = new File(MaryProperties.getFilename("cache.file", "maryCache"));
File directory = targetFile.getParentFile();
if (!directory.isDirectory()) {
directory.mkdirs();
}
maryCache = new MaryCache(targetFile, MaryProperties.getBoolean("cache.clearOnStart", false));
} catch (Exception e) {
MaryUtils.getLogger(MaryCache.class).warn("Cannot set up cache", e);
}
}
return maryCache;
}
/**
* Indicate whether there is a MaryCache currently available.
*
* @return true if there is a MaryCache, false otherwise.
*/
public static boolean haveCache() {
return maryCache != null;
}
// //////////////////////////// non-static code /////////////////////////////
private Connection connection;
/**
* Create a MaryCache with the given file prefix. This constructor is public only for tests; it should not normally be called.
* User code should call {@link #getCache()} instead. TODO: Find a more elegant way to create a custom MaryCache from test
* code.
*
* @param cacheFile
* the file name prefix with which to create the cache database.
* @param clearCache
* if true, clear the cache; if false, keep it.
* @throws ClassNotFoundException
* if the HSQL JDBC driver is not in the classpath.
* @throws SQLException
* if the database connection cannot be set up
*/
public MaryCache(File cacheFile, boolean clearCache) throws ClassNotFoundException, SQLException {
// Load the HSQL Database Engine JDBC driver
Class.forName("org.hsqldb.jdbcDriver");
connection = DriverManager.getConnection("jdbc:hsqldb:" + cacheFile.toURI().toString(), "sa", "");
boolean mustCreateTable = false;
if (clearCache) {
Statement st = connection.createStatement();
st.executeUpdate("DROP TABLE MARYCACHE IF EXISTS");
st.close();
mustCreateTable = true;
} else { // don't clear -- check if table exists
DatabaseMetaData dbInfo = connection.getMetaData();
ResultSet rs = dbInfo.getTables(null, null, "MARYCACHE", new String[] { "TABLE" });
if (rs.next()) {
// table exists
} else {
mustCreateTable = true;
}
}
if (mustCreateTable) {
String query = "CREATE CACHED TABLE MARYCACHE (id INTEGER IDENTITY, " + "inputtype VARCHAR(50), "
+ "outputtype VARCHAR(50), " + "locale VARCHAR(10), " + "voice VARCHAR(100), "
+ "outputparams VARCHAR(1000), " + "style VARCHAR(50), " + "effects VARCHAR(1000), "
+ "inputtext LONGVARCHAR, " + "outputtext LONGVARCHAR, " + "outputaudio LONGVARBINARY, "
+ "UNIQUE(inputtype, outputtype, locale, voice, outputparams, style, effects, inputtext)" + ")";
update(query);
}
}
/**
* Carry out an UPDATE SQL command on the database.
*
* @param query
* the UPDATE SQL command to carry out
* @throws SQLException
* if there is a problem executing the update.
*/
private synchronized void update(String query) throws SQLException {
Statement st = connection.createStatement();
int ok = st.executeUpdate(query);
if (ok == -1) {
throw new SQLException("DB problem with query: " + query);
}
st.close();
}
/**
* Insert a record of a MARY request producing data of type text into the cache. If a record with the same lookup keys (i.e.,
* all parameters everything except outputtext) exists already, this call does nothing.
*
* @param inputtype
* the request's input type. Must not be null.
* @param outputtype
* the request's output type, which must be a text type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @param outputtext
* the request's output text. Must not be null.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if the record could not be entered into the cache.
*/
public void insertText(String inputtype, String outputtype, String locale, String voice, String inputtext, String outputtext)
throws SQLException {
insertText(inputtype, outputtype, locale, voice, null, null, null, inputtext, outputtext);
}
/**
* Insert a record of a MARY request producing data of type text into the cache. If a record with the same lookup keys (i.e.,
* all parameters everything except outputtext) exists already, this call does nothing.
*
* @param inputtype
* the request's input type. Must not be null.
* @param outputtype
* the request's output type, which must be a text type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param outputparams
* optionally, any output parameters. Can be null.
* @param style
* optionally, any style. Can be null.
* @param effects
* optionally, any effects. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @param outputtext
* the request's output text. Must not be null.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if the record could not be entered into the cache.
*/
public synchronized void insertText(String inputtype, String outputtype, String locale, String voice, String outputparams,
String style, String effects, String inputtext, String outputtext) throws SQLException {
if (inputtype == null || outputtype == null || locale == null || voice == null || inputtext == null || outputtext == null) {
throw new NullPointerException("Null argument");
}
// Need to verify, here in the synchronized code, once again that really we don't have this entry already.
// If we do, we ignore this call.
if (lookupText(inputtype, outputtype, locale, voice, outputparams, style, effects, inputtext) != null) {
return;
}
String query = "INSERT INTO MARYCACHE (inputtype, outputtype, locale, voice, outputparams, style, effects, inputtext, outputtext) VALUES ('"
+ inputtype
+ "','"
+ outputtype
+ "','"
+ locale
+ "','"
+ voice
+ "','"
+ outputparams
+ "','"
+ style
+ "','"
+ effects + "',?,?)";
PreparedStatement st = connection.prepareStatement(query);
// We set the input and output text separately because they could contain single quote characters
st.setString(1, inputtext);
st.setString(2, outputtext);
st.executeUpdate();
st.close();
}
/**
* Insert a record of a MARY request producing data of output type AUDIO into the cache. If a record with the same lookup keys
* (i.e., all parameters everything except audio) exists already, this call does nothing.
*
* @param inputtype
* the request's input type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @param audio
* the request's output data. Must not be null.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if the record could not be entered into the cache.
*/
public void insertAudio(String inputtype, String locale, String voice, String inputtext, byte[] audio) throws SQLException {
insertAudio(inputtype, locale, voice, null, null, null, inputtext, audio);
}
/**
* Insert a record of a MARY request producing data of output type AUDIO into the cache. If a record with the same lookup keys
* (i.e., all parameters everything except audio) exists already, this call does nothing.
*
* @param inputtype
* the request's input type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param outputparams
* optionally, any output parameters. Can be null.
* @param style
* optionally, any style. Can be null.
* @param effects
* optionally, any effects. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @param audio
* the request's output data. Must not be null.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if the record could not be entered into the cache.
*/
public synchronized void insertAudio(String inputtype, String locale, String voice, String outputparams, String style,
String effects, String inputtext, byte[] audio) throws SQLException {
if (inputtype == null || locale == null || voice == null || inputtext == null) {
throw new NullPointerException("Null argument");
}
// Need to verify, here in the synchronized code, once again that really we don't have this entry already.
// If we do, we ignore this call.
if (lookupAudio(inputtype, locale, voice, outputparams, style, effects, inputtext) != null) {
return;
}
String query = "INSERT INTO MARYCACHE (inputtype, outputtype, locale, voice, outputparams, style, effects, inputtext, outputaudio) VALUES('"
+ inputtype
+ "','AUDIO','"
+ locale
+ "','"
+ voice
+ "','"
+ outputparams
+ "','"
+ style
+ "','"
+ effects
+ "',?,?)";
PreparedStatement st = connection.prepareStatement(query);
st.setString(1, inputtext);
st.setBytes(2, audio);
st.executeUpdate();
st.close();
}
/**
* Carry out a lookup in the cache with the given parameters.
*
* @param inputtype
* the request's input type. Must not be null.
* @param outputtype
* the request's output type, which must be a text type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @return the output text associated with the with the given record, or null if the cache does not contain a record with
* these keys.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if there is a problem querying the cache.
*/
public String lookupText(String inputtype, String outputtype, String locale, String voice, String inputtext)
throws SQLException {
return lookupText(inputtype, outputtype, locale, voice, null, null, null, inputtext);
}
/**
* Carry out a lookup in the cache with the given parameters.
*
* @param inputtype
* the request's input type. Must not be null.
* @param outputtype
* the request's output type, which must be a text type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param outputparams
* optionally, any output parameters. Can be null.
* @param style
* optionally, any style. Can be null.
* @param effects
* optionally, any effects. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @return the output text associated with the with the given record, or null if the cache does not contain a record with
* these keys.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if there is a problem querying the cache.
*/
public synchronized String lookupText(String inputtype, String outputtype, String locale, String voice, String outputparams,
String style, String effects, String inputtext) throws SQLException {
if (inputtype == null || outputtype == null || locale == null || voice == null || inputtext == null) {
throw new NullPointerException("Null argument");
}
String outputtext = null;
String query = "SELECT outputtext FROM marycache WHERE inputtype = '" + inputtype + "' AND outputtype = '" + outputtype
+ "' AND locale = '" + locale + "' AND voice = '" + voice + "' AND outputparams = '" + outputparams
+ "' AND style = '" + style + "' AND effects = '" + effects + "' AND inputtext = ?";
PreparedStatement st = connection.prepareStatement(query);
st.setString(1, inputtext);
ResultSet results = st.executeQuery();
if (results.next()) { // we expect only a single result, if any, so no while loop
outputtext = results.getString(1);
}
st.close();
return outputtext;
}
/**
* Carry out a lookup in the cache with the given parameters, for a request with output type AUDIO.
*
* @param inputtype
* the request's input type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @return the output text associated with the with the given record, or null if the cache does not contain a record with
* these keys.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if there is a problem querying the cache.
*/
public byte[] lookupAudio(String inputtype, String locale, String voice, String inputtext) throws SQLException {
return lookupAudio(inputtype, locale, voice, null, null, null, inputtext);
}
/**
* Carry out a lookup in the cache with the given parameters, for a request with output type AUDIO.
*
* @param inputtype
* the request's input type. Must not be null.
* @param locale
* the locale of the request. Must not be null.
* @param voice
* the voice of the request. Can be null.
* @param outputparams
* optionally, any output parameters. Can be null.
* @param style
* optionally, any style. Can be null.
* @param effects
* optionally, any effects. Can be null.
* @param inputtext
* the request's input text. Must not be null.
* @return the output text associated with the with the given record, or null if the cache does not contain a record with
* these keys.
* @throws NullPointerException
* if one of the fields is null which must be non-null.
* @throws SQLException
* if there is a problem querying the cache.
*/
public synchronized byte[] lookupAudio(String inputtype, String locale, String voice, String outputparams, String style,
String effects, String inputtext) throws SQLException {
if (inputtype == null || locale == null || voice == null || inputtext == null) {
throw new NullPointerException("Null argument");
}
byte[] audio = null;
String query = "Select outputaudio FROM marycache WHERE inputtype = '" + inputtype
+ "' AND outputtype = 'AUDIO' AND locale = '" + locale + "' AND voice = '" + voice + "' AND outputparams = '"
+ outputparams + "' AND style = '" + style + "' AND effects = '" + effects + "' AND inputtext = ?";
PreparedStatement st = connection.prepareStatement(query);
st.setString(1, inputtext);
ResultSet results = st.executeQuery();
if (results.next()) {
audio = results.getBytes(1);
}
return audio;
}
/**
* Shut down the cache. After this has been called, any further calls to the object will throw exceptions.
*
* @throws SQLException
* if there is a problem executing the database SHUTDOWN command.
*/
public void shutdown() throws SQLException {
Statement st = connection.createStatement();
st.execute("SHUTDOWN");
connection.close(); // if there are no other open connection
}
/**
* @param args
* args
* @throws SQLException
* SQLException
* @throws MalformedURLException
* MalformedURLException
* @throws ClassNotFoundException
* ClassNotFoundException
*/
public static void main(String[] args) throws SQLException, MalformedURLException, ClassNotFoundException {
MaryCache c = new MaryCache(new File("/Users/marc/Desktop/testdb/testDB"), false);
// c.insertText("TEXT", "RAWMARYXML", "de", "de1", "Welcome to the world of speech synthesis", " ");
String text = c.lookupText("TEXT", "RAWMARYXML", "de", "de1", "Welcome to the world of speech synthesis");
System.out.println("looked up text: " + text);
byte[] zeros = new byte[200000];
// c.insertAudio("TEXT", "de", "de1", "some dummy text", zeros);
byte[] newones = c.lookupAudio("TEXT", "de", "de1", "some dummy text");
System.out.println("Retrieved binary data of length " + newones.length);
c.shutdown();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy