Every one talk about Backup Hsqldb outside, but what i require is to Backup the embeded files...
I'm using Spring JPA, and the application is always running, so files are in use, also since there is no DBMS, i'm wonder if there are ways to backup and restore?
If there are, please guide me...
Otherwise, i though of copying database file, after somehow (don't know how) putting spring JPA in offline mode, and then ZIP those file, which i don't know in java, and then let user to download it, if spring allow's it... somehow (as i use stand alone spring boot, which is a single file, and it doesn't offer lot of those fancy folder, which we can point to them as website url...)
In the end in any scenario i want to send the file to client.
Sorry if i know none of this, i came from C#, and after 5 years, it's my second time using Java, which i never beem pro in it.
UPDATE
Although i'm not sure if i can make a zip file from running database, and store it in that place... I write this code through searching, i find several method that returns current directory, but non of them point to directory i want... one of them, in debug it point to very inner location, like targer/class/x/y/z, after i package it to jar file, it may be different, another one point to C/..../temp, ... i need to get write to where my DB file is located, then pass those file to make zip file function, and tell user to download the files
#RestController
#RequestMapping(value = "/rest/database-manager")
public class DatabaseManager {
private ServletContext servletContext;
private final Environment env;
#Autowired
public DatabaseManager(Environment env, ServletContext servletContext) {
this.env = env;
this.servletContext = servletContext;
}
#RequestMapping(value = "/get-backup", method=RequestMethod.GET)
private FileSystemResource getBackup() throws IOException {
//String directory = DemoApplication.class.getResource("").getPath();
String outputLocation = servletContext.getRealPath("./");
String dataBaseFilePath = servletContext.getRealPath(env.getProperty("application.database-file-location"));
Calendar cal = new GregorianCalendar();
String zipFile = outputLocation + "/backup-"
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.YEAR)), 4, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.MONTH)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0")
+ "-"
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.HOUR)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.SECOND)), 2, "0")
+ ".zip";
ZipUtil.ToZip(new String[]{""}, zipFile);
return new FileSystemResource(zipFile);
}
}
zip function:
public class ZipUtil {
public static void ToZip(String inputFiles[], String outputFile) throws IOException {
//create byte buffer
byte[] buffer = new byte[1024];
/*
* To create a zip file, use
*
* ZipOutputStream(OutputStream out)
* constructor of ZipOutputStream class.
*/
//create object of FileOutputStream
FileOutputStream fout = new FileOutputStream(outputFile);
//create object of ZipOutputStream from FileOutputStream
ZipOutputStream zout = new ZipOutputStream(fout);
for (int i = 0; i < inputFiles.length; i++) {
//create object of FileInputStream for source file
FileInputStream fin = new FileInputStream(inputFiles[i]);
/*
* To begin writing ZipEntry in the zip file, use
*
* void putNextEntry(ZipEntry entry)
* method of ZipOutputStream class.
*
* This method begins writing a new Zip entry to
* the zip file and positions the stream to the start
* of the entry data.
*/
zout.putNextEntry(new ZipEntry(inputFiles[i]));
/*
* After creating entry in the zip file, actually
* write the file.
*/
int length;
while ((length = fin.read(buffer)) > 0) {
zout.write(buffer, 0, length);
}
/*
* After writing the file to ZipOutputStream, use
*
* void closeEntry() method of ZipOutputStream class to
* close the current entry and position the stream to
* write the next entry.
*/
zout.closeEntry();
//close the InputStream
fin.close();
}
//close the ZipOutputStream
zout.close();
}
}
Full Answer:
I'm not sure if produce do anything, as i directly write into response inside, and return void.
My Response Method:
#RequestMapping(value = "/get-backup", method = RequestMethod.GET)
private void getBackup(HttpServletResponse response) throws IOException {
/*//String directory = DemoApplication.class.getResource("").getPath();
String outputLocation = servletContext.getRealPath("./");
String dataBaseFilePath = servletContext.getRealPath(env.getProperty("application.database-file-location"));
Calendar cal = new GregorianCalendar();
String zipFile = outputLocation + "/backup-"
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.YEAR)), 4, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.MONTH)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0")
+ "-"
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.HOUR)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.SECOND)), 2, "0")
+ ".zip";
SQLQuery query = session.createSQLQuery("BACKUP DATABASE TO '/tmp/backup.tar.gz' BLOCKING");
query.executeUpdate();*/
File zipFile = null;
Calendar cal = new GregorianCalendar();
String prefix = "DBK-"
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.YEAR)), 4, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.MONTH)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.DAY_OF_MONTH)), 2, "0")
+ "-"
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.HOUR)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.MINUTE)), 2, "0")
+ StrMgr.leftPad(String.valueOf(cal.get(Calendar.SECOND)), 2, "0");
String suffix = ".tar.gz";
zipFile = File.createTempFile(prefix, suffix);
zipFile.delete();
databaseManagerRepository.Backup(zipFile.getAbsolutePath());
response.setContentType("application/gzip");
response.setHeader("Content-disposition", "attachment; filename=" + zipFile.getName());
// OutputStream out = response.getOutputStream();
// FileInputStream in = new FileInputStream(zipFile);
/*
* copy from in to out
*/
OutputStream out = null;
FileInputStream in = null;
try {
out = response.getOutputStream();
in = new FileInputStream(zipFile);
byte[] buffer = new byte[4096]; // To hold file contents
int bytes_read; // How many bytes in buffer
// Read a chunk of bytes into the buffer, then write them out,
// looping until we reach the end of the file (when read() returns
// -1). Note the combination of assignment and comparison in this
// while loop. This is a common I/O programming idiom.
while ((bytes_read = in.read(buffer)) != -1)
// Read until EOF
out.write(buffer, 0, bytes_read); // write
}
catch (Exception ex){
System.out.print(ex.getMessage());
}
// Always close the streams, even if exceptions were thrown
finally {
if (in != null)
try {
in.close();
} catch (IOException e) {
;
}
if (out != null)
try {
out.close();
} catch (IOException e) {
;
}
}
zipFile.delete();
}
My Backup Native SQL Action Executor
#Repository
public class DatabaseManagerRepository {
#PersistenceContext
private EntityManager entityManager;
/*The query force us to use transaction, and since the DB is online and we use spring, it also force us to use spring transaction*/
#Transactional(rollbackFor = {Exception.class})
public void Backup(String outputDir) {
//NOT BLOCKING -> For large database, backup is performed while the database perform other operations
//AS FILES -> We only define directory not the file itself
Query q = entityManager.createNativeQuery("BACKUP DATABASE TO '" + outputDir + "' BLOCKING"/*" AS FILES"*/);
q.executeUpdate();
}
}
Backup is the same with an HSQLDB Server or embedded database. You execute the SQL statement:
BACKUP DATABASE TO <directory name> BLOCKING AS FILES
The directory name is a path to the target directory to store the backup files. For example BACKUP DATABASE TO 'C://db_backups/' BLOCKING AS FILES
http://hsqldb.org/doc/2.0/guide/management-chapt.html#mtc_online_backup
The AS FILES backup database creates a set of files which you can zip.
I am writing a web app that I would like to be able to import a csv file into a database from a jsp. Previously I have used the following code to insert the csv into the database.
LOAD DATA LOCAL INFILE "/myFileLocation.csv"
INTO TABLE myTable
COLUMNS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
ESCAPED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES;
Which works great when I have the file locally.
My question, when I upload the csv file in my jsp as a multipart. Is it possible for me to pass that PartItem file as a variable and replace the "/myFileLocation.csv" with the PartItem files temp location?
I can see the temp location when I debug and view the PartItem file which resides in repository/path under the variables table. Is this at all possible to access or do i need to parse the csv and insert it into the database that way?
I ended up finding a way to make this work. Not sure if it's the best solution but its working as I envisioned. Basically I create a string pointing to an assets folder I created in the web/resources like this.
final String mainPath = this.getServletContext().getRealPath("resources/assets");
Then I read the uploaded file, check to see if the file already exists in my assets folder, if it does I delete it.
Part filePart = request.getPart("csvFile");
String path = mainPath + "/" + filePart.getSubmittedFileName();
File fileTemp = new File(path);
if(fileTemp.exists()){
fileTemp.delete();
}
Lastly I read the uploaded file and write a new file in the location I directed it to which in this case is the assets folder I created like this.
final String fileName = filePart.getSubmittedFileName();
File convFile = new File(filePart.getSubmittedFileName());
FileOutputStream fos = new FileOutputStream(convFile);
OutputStream out = null;
InputStream filecontent= null;
try{
out = new FileOutputStream(new File(mainPath + File.separator + fileName));
filecontent = filePart.getInputStream();
int read = 0;
final byte[] bytes = new byte[1024];
while((read = filecontent.read(bytes)) != -1){
out.write(bytes, 0, read);
}
} catch (FileNotFoundException fne) {
} finally {
if (out != null) {
out.close();
}
if (filecontent != null) {
filecontent.close();
}
}
After that I just passed a string containing the path to the file with the file name to the DAO I created where I was able to utilize the sql statement I had posted above.
Like I stated before, not sure if this is the best way to do this but it seems to be working fine for me and none of my java code is contained within my jsp. If anyone has a better way of doing this or sees something wrong with what I did here let me know, I'd be very interested to hear about it.
I am trying to transfer a SQLite database into an app by downloading it and then unzipping it to the correct location. I was successful in transferring the DB when it was unzipped. The error I get is that it cannot find any of the tables I query. I have also been successful in unzipping and reading normal text files.
The DB has Hebrew and English, but that has not caused problems before. The bilingual DB was copied successfully when it was not zipped and bilingual texts have been successfully unzipped and read. Still, it is a possibility that there is an encoding problem going on. That seems weird to me, because as you can see below in the code, I'm just copying the bytes directly.
-EDIT-
Let's say the prezipped db is called test1.db. I zipped it, put it in the app, unzipped it and called that test2.db. when I ran a diff command on these two, there were no differences. So there must be a technical issue with the way android is reading the file / or maybe encoding issue on android that doesn't exist on pc?
I hate to do a code dump, but i will post both my copyDatabase() function (which works). That is what I used previously running it on an unzipped DB file. I put it here as comparison. Now I'm trying to use unzipDatabase() function (which doesn't work), and use it on a zipped DB file. The latter function was copied from How to unzip files programmatically in Android?
private void copyDatabase() throws IOException{
String DB_NAME = "test.db";
String DB_PATH = "/data/data/org.myapp.myappname/databases/";
//Open your local db as the input stream
InputStream myInput = myContext.getAssets().open(DB_NAME);
// Path to the just created empty db
String outFileName = DB_PATH + DB_NAME;
//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);
//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}
private boolean unzipDatabase(String path)
{
String DB_NAME = "test.zip";
InputStream is;
ZipInputStream zis;
try
{
String filename;
is = myContext.getAssets().open(DB_NAME);
zis = new ZipInputStream(is);
ZipEntry ze;
byte[] buffer = new byte[1024];
int count;
while ((ze = zis.getNextEntry()) != null)
{
// write to a file
filename = ze.getName();
// Need to create directories if not exists, or
// it will generate an Exception...
if (ze.isDirectory()) {
Log.d("yo",path + filename);
File fmd = new File(path + filename);
fmd.mkdirs();
continue;
}
OutputStream fout = new FileOutputStream(path + filename);
// reading and writing zip
while ((count = zis.read(buffer)) != -1)
{
fout.write(buffer, 0, count);
}
fout.flush();
fout.close();
zis.closeEntry();
}
zis.close();
}
catch(IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
So still don't know why, but the problem is solved if I first delete the old copy of the database (located at DB_PATH + DB_NAME) and then unzip the new one there. I didn't need to do this when copying it directly.
so yay, it was a file overwriting issue...If someone knows why, feel free to comment
I have JBoss running as application server and somewhere on my HD there is a PDF file, that gets created when the user clicks on a specific action. Let's say the file is here: C:/PDF/doonot/10.07.2012/doonot.pdf. How can I offer this file as download? I already did it for a CSV file, but I don't know how to do it with PDF.
Any help is much appreciated.
as i wrote on Is there a common way to download all types of files in jsp?
you can use something like this:
public HttpServletResponse getFile (HttpServletRequest request ,HttpServletResponse httpServletResponse, .......){
HttpServletResponse response = httpServletResponse;
InputStream in =/*HERE YOU READ YOUR FILE AS BinaryStream*/
String filename = "";
String agent = request.getHeader("USER-AGENT");
if (agent != null && agent.indexOf("MSIE") != -1)
{
filename = URLEncoder.encode(/*THIS IS THE FILENAME SHOWN TO THE USER*/, "UTF8");
response.setContentType("application/x-download");
response.setHeader("Content-Disposition","attachment;filename=" + filename);
}
else if ( agent != null && agent.indexOf("Mozilla") != -1)
{
response.setCharacterEncoding("UTF-8");
filename = MimeUtility.encodeText(/*THIS IS THE FILENAME SHOWN TO THE USER*/, "UTF8", "B");
response.setContentType("application/force-download");
response.addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
}
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
byte by[] = new byte[32768];
int index = in.read(by, 0, 32768);
while (index != -1) {
out.write(by, 0, index);
index = in.read(by, 0, 32768);
}
out.flush();
return response;
}
UPDATE:
Dont forget that you can use the InputStream as this:
// read local file into InputStream
InputStream inputStream = new FileInputStream("c:\\SOMEFILE.xml");
or you can use it even like this
//read from database
Blob blob = rs.getBlob(1);
InputStream in = blob.getBinaryStream();
You can simply write a servlet wich read the pdf and write it to the response output stream.
Exemple here : http://www.java-forums.org/blogs/servlet/668-how-write-servlet-sends-file-user-download.html
Yes Gustav is right. Java doesn't discriminate amongst file types. A file is a file, if you did it for csv, it should also work for pdf.
Use Case
I need to package up our kml which is in a String into a kmz response for a network link in Google Earth. I would like to also wrap up icons and such while I'm at it.
Problem
Using the implementation below I receive errors from both WinZip and Google Earth that the archive is corrupted or that the file cannot be opened respectively. The part that deviates from other examples I'd built this from are the lines where the string is added:
ZipEntry kmlZipEntry = new ZipEntry("doc.kml");
out.putNextEntry(kmlZipEntry);
out.write(kml.getBytes("UTF-8"));
Please point me in the right direction to correctly write the string so that it is in doc.xml in the resulting kmz file. I know how to write the string to a temporary file, but I would very much like to keep the operation in memory for understandability and efficiency.
private static final int BUFFER = 2048;
private static void kmz(OutputStream os, String kml)
{
try{
BufferedInputStream origin = null;
ZipOutputStream out = new ZipOutputStream(os);
out.setMethod(ZipOutputStream.DEFLATED);
byte data[] = new byte[BUFFER];
File f = new File("./icons"); //folder containing icons and such
String files[] = f.list();
if(files != null)
{
for (String file: files) {
LOGGER.info("Adding to KMZ: "+ file);
FileInputStream fi = new FileInputStream(file);
origin = new BufferedInputStream(fi, BUFFER);
ZipEntry entry = new ZipEntry(file);
out.putNextEntry(entry);
int count;
while((count = origin.read(data, 0, BUFFER)) != -1) {
out.write(data, 0, count);
}
origin.close();
}
}
ZipEntry kmlZipEntry = new ZipEntry("doc.kml");
out.putNextEntry(kmlZipEntry);
out.write(kml.getBytes("UTF-8"));
}
catch(Exception e)
{
LOGGER.error("Problem creating kmz file", e);
}
}
Bonus points for showing me how to put the supplementary files from the icons folder into a similar folder within the archive as opposed to at the same layer as the doc.kml.
Update Even when saving the string to a temp file the errors occur. Ugh.
Use Case Note The use case is for use in a web app, but the code to get the list of files won't work there. For details see how-to-access-local-files-on-server-in-jboss-application
You forgot to call close() on ZipOutputStream. Best place to call it is the finally block of the try block where it's been created.
Update: To create a folder, just prepend its name in the entry name.
ZipEntry entry = new ZipEntry("icons/" + file);