Export a writable sqlite database - java

Is there a way to export a writable database? I need to use the database I have exported from the phone in a Visual Studio app as part of the system. Its bad, I know, but its the only I could do my project. This is the code i use to export the database from the SQLiteImporterExporter library
public void exportDataBase(String path) {
InputStream myInput = null;
OutputStream myOutput = null;
try {
String inFileName = DB_PATH + DB_NAME;
myInput = new FileInputStream(inFileName);
String outFileName = path + DB_NAME;
myOutput = new FileOutputStream(outFileName);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
if (exportListener != null)
exportListener.onSuccess("Successfully Exported");
} catch (Exception e) {
if (exportListener != null)
exportListener.onFailure(e);
} finally {
try {
// Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
} catch (Exception ex) {
if (exportListener != null)
exportListener.onFailure(ex);
}
}
}

Is there a way to export a writable database?
From your code, assuming that it's working, then that's what you are doing. It is also assumed that you are ensuring that the database is not in-use elsewhere and that it has been closed.
That is, an SQLite database is a single file, copy that file and you can then use that database anywhere where you have SQLite. The writable/readable concept (i.e. getWritableDatabase v getReadableDatabase) is one of the more common mis-conceptions. The latter will in most cases get a writable database, it will only return a read only database if the database cannot be written too e.g. (full disk). As per :-
Create and/or open a database. This will be the same object returned
by getWritableDatabase() unless some problem, such as a full disk,
requires the database to be opened read-only. In that case, a
read-only database object will be returned. If the problem is fixed, a
future call to getWritableDatabase() may succeed, in which case the
read-only database object will be closed and the read/write object
will be returned in the future.
getReadableDatabase
Exceptions/considerations would be :-
If the database were encrypted, in which case you would use the encryption code/extension along with the key.
If you use in-memory/temporary tables, in this case AND if you needed these in-memory/temporary tables, you could either create a copy database but changing in-memory/temporary to be permanent.
SQLite does have a backup API, which does this. However, I don't believe that the SQLite API in Android implements the backup API though (so it could well be a bigger pain to try utilising it, than implementing the copy method).
being on Android, there will be an additional table in the database named android_metadata, this simply stores the locale and can be ignored elsewhere.

Related

How can I add a specific file to a specific directory using Java? [duplicate]

This question already has answers here:
How do I create a file and write to it?
(35 answers)
Closed 1 year ago.
I'm working on a new function on a system, and at the moment I need to pick a file, and save on a folder in the user C:. The process happens as it follows, the user uploads a file into the system, that file can be anything, text, image, except videos, and now it is saved in the system database, but my boss wants to change that process so I need to save on a specific folder on the user C:, I already created the specific folder, but I don't know how to save the file in that created folder.
So the code for uploading a file as it follows:
public void uploadArquivo(FileUploadEvent event) {
byte[] bytes = null;
try {
File targetFolder = new File(System.getProperty("java.io.tmpdir"));
if (!targetFolder.exists()) {
if (targetFolder.mkdirs()) {
FacesMessageUtil.novaMensagem("Atenção", "Não foi possível criar pasta temporária!");
return;
}
}
targetFolder.mkdirs();
OutputStream out;
try (InputStream inputStream = event.getFile().getInputstream()) {
out = new FileOutputStream(new File(targetFolder, event.getFile().getFileName()));
int read;
bytes = new byte[10485760];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inputStream.close();
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace(System.out);
}
AnexoEmpreendimento anexo = new AnexoEmpreendimento();
anexo.setNomeArquivo(event.getFile().getFileName());
anexo.setTamanhoArquivo(event.getFile().getSize());
anexo.setArquivo(bytes);
anexos.add(anexo);
}
Well, it depends on what you actually 'have'. A web submit form? Which web framework do you have then? A BLOB in a db? Which DB engine do you have and which DB framework are you using in java to interact with it, etcetera.
Most libraries will let you obtain either an InputStream or a byte[] (if they offer both, you want the InputStream).
You can write an inputstream to a file, or a byte[] to a file, as follows:
import java.nio.file.*;
public class Example {
static final Path MY_DIR = Paths.get("C:/path/to/your/dir");
void writeByteArr(byte[] data) throws IOException {
Path toWrite = MY_DIR.resolve("filename.dat");
Files.write(toWrite, data);
}
void writeInputStream(InputStream data) throws IOException {
Path toWrite = MY_DIR.resolve("filename.dat");
Files.copy(data, toWrite);
}
}
In the unlikely case the data you 'get' is neither in byte[] nor InputStream form you're going to have to elaborate quite a bit on how the data gets to your code.

Unable to delete text file using delete()

I am trying to transfer the data from old textfile to new textfile. Although the code below is able to transfer successfully, it does not delete the old textfile. May I know why is this so?
private void dataTransfer(String oldFilePath, String newFilePath) {
byte[] buffer = new byte[10000];
try {
FileInputStream fileInput = new FileInputStream(oldFilePath);
BufferedInputStream bufferedInput = new BufferedInputStream(fileInput);
FileOutputStream fileOutput = new FileOutputStream(newFilePath);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(fileOutput);
while(true) {
int length = fileInput.read(buffer);
if(length == -1) {
break;
} else {
bufferedOutput.write(buffer);
bufferedOutput.flush();
}
}
fileInput.close();
bufferedInput.close();
fileOutput.close();
bufferedOutput.close();
File oldFile = new File(oldFilePath);
oldFile.delete();
} catch (IOException e) {
e.printStackTrace();
System.out.println(ERROR_TRANSFER_DATA);
}
}
Update the JRE and JDK, make sure you have the rights on the file. Try with a file created by you.
Also, add a catch block for SecurityException
For deleting a file it should work fine but for deleting a directory you have to make sure that Directory is Empty.
You can use the following code block. It works, though don't know. Even without setWritable, it works,
oldFile.setWritable(true);
if(!oldFile.delete()){
System.out.println("de;eted");
}
According to Oracle's docs, the delete method does not guarantee that it will delete the file.
http://docs.oracle.com/javase/7/docs/api/java/io/File.html#delete()
Deleting a file will fail if:
file does not exist
there is a lock on that file it might be opened by another process
file does not exist on the disk
you don't have enough permissions to delete that file (in this case a SecurityException is thrown)
I agree with #panagdu that you might not have sufficient rights to delete the file.
Just as a fluke try closing bufferedStream before fileInputStream
like
bufferedInput.close();
fileInput.close();
bufferedOutput.close();
fileOutput.close();
But I don't think this will help.
Test your code for files with sufficient permission. For example Java does not allow the delete() for system files.

java.io.FileNotFoundException: /tmp/ (Too many open files)

I have a rest service in Java EE and for some weird backward compatibility reasons I have to return an .mdb file from a URL request after adding some rows inside it.
At first I simply opened an mdb file, cleared all rows in it, wrote my rows and returned it to the caller, however I realized the .mdb kept growing this way because Access doesn't purge the rows on deletion but only erases it and the library I am using (Jackcess) doesn't support purging completely the rows.
So I switched to creating a copy of an empty .mdb file with java.io.File.createTempFile() and returning it however a dangling pointer to the file in the /tmp/ folder is left and after several days I get a
java.io.FileNotFoundException: /tmp/tmpdb.mdb04949499 (Too many open files)
The only solutions I found so far are:
Set MAX_FILE_HANDLES_FOR_READ_ENDS_MAP to a very high number (which only postpones the problem)
deleting the temp file, which however is not viable because I return it from a function and once returned I lose control of the pointer.
below what I currently have:
GET
#Path("/get/database/{filename}")
#Produces("application/jet")
public StreamingOutput getDatabase(#PathParam("filename") String fileName)
{
//access files increase indefinitely in size because deleted rows are simply marked "deleted" and not removed
//so we create a temporary file equal to the template .mdb file and use it instead
java.io.File myDBFile = null;
try
{
java.io.File templateDBFile = new java.io.File(url + "resources/clean_tmpdb.mdb");
myDBFile = java.io.File.createTempFile("tmpdb", ".mdb");
myDBFile.deleteOnExit(); //useless hint
FileChannel src = new FileInputStream(templateDBFile).getChannel();
FileChannel dest = new FileOutputStream(myDBFile).getChannel();
dest.transferFrom(src, 0, src.size());
}
catch (IOException ex)
{
Logger.getLogger(FileResource.class.getName()).log(Level.SEVERE, null, ex);
}
finally
{
if (src != null)
{
try
{
src.close();
}
catch (IOException ex)
{
Logger.getLogger(FileResource.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (dest != null)
{
try
{
dest.close();
}
catch (IOException ex)
{
Logger.getLogger(FileResource.class.getName()).log(Level.SEVERE, null, ex);
}
}
/* work on the file inserting rows */
return new FileStreamingOutput(myDBFile);
}
EDIT: found a similar question, with a vague accepted answer: How to delete file after REST response, the accepted answer is "just write directly to the output stream contained in the Response."
You aren't closing either src or dest. So as to ensure they are closed, close them in finally blocks, or use the try-with-resources syntax.
return new FileStreamingOutput(myDBFile);
/* here I should call myDBFile.close(); and myDBFile.delete(); */
Here you can't call myDBFile.close(), as there is no such method. You can't call myDBFile.delete() either, as otherwise the caller will receive a File that doesn't exist. If the File needs to be deleted, the caller will have to do it. Your stated requirement doesn't make sense.

Intelligently serving jar files from a web server

I am writing a simple (generic) wrapper Java class that will execute on various computers separate from a deployed web server. I want to download the latest version of a jar file that is the application from that associated Web Server (currently Jetty 8).
I have code like this:
// Get the jar URL which contains the application
URL jarFileURL = new URL("jar:http://localhost:8081/myapplication.jar!/");
JarURLConnection jcl = (JarURLConnection) jarFileURL.openConnection();
Attributes attr = jcl.getMainAttributes();
String mainClass = (attr != null)
? attr.getValue(Attributes.Name.MAIN_CLASS)
: null;
if (mainClass != null) // launch the program
This works well, except that myapplication.jar is a large jar file (a OneJar jarfile, so a lot is in there). I would like this to be as efficient as possible. The jar file isn't going to change very often.
Can the jar file be saved to disk (I see how to get a JarFile object, but not to save it)?
More importantly, but related to #1, can the jar file be cached somehow?
2.1 can I (easily) request the MD5 of the jar file on the web server and only download it when that has changed?
2.2 If not is there another caching mechanism, maybe request only the Manifest? Version/Build info could be stored there.
If anyone done something similar could you sketch out in as much detail what to do?
UPDATES PER INITIAL RESPONSES
The suggestion is to use an If-Modified-Since header in the request and the openStream method on the URL to get the jar file to save.
Based on this feedback, I have added one critical piece of info and some more focused questions.
The java program I am describing above runs the program downloaded from the jar file referenced. This program will run from around 30 seconds to maybe 5 minutes or so. Then it is done and exits. Some user may run this program multiple times per day (say even up to 100 times), others may run it as infrequently as once every other week. It should still be smart enough to know if it has the most current version of the jar file.
More Focused Questions:
Will the If-Modified-Since header still work in this usage? If so, will I need completely different code to add that? That is, can you show me how to modify the code presented to include that? Same question with regard to saving the jar file - ultimately I am really surprised (frustrated!) that I can get a JarFile object, but have no way to persist it - will I even need the JarURLConnection class?
Bounty Question
I didn't initially realize the precise question I was trying to ask. It is this:
How can I save a jar file from a web server locally in a command-line program that exits and ONLY update that jar file when it has been changed on the server?
Any answer that, via code examples, shows how that may be done will be awarded the bounty.
Yes, the file can be saved to the disk, you can get the input stream using the method openStream() in URL class.
As per the comment mentioned by #fge there is a way to detect whether the file is modified.
Sample Code:
private void launch() throws IOException {
// Get the jar URL which contains the application
String jarName = "myapplication.jar";
String strUrl = "jar:http://localhost:8081/" + jarName + "!/";
Path cacheDir = Paths.get("cache");
Files.createDirectories(cacheDir);
Path fetchUrl = fetchUrl(cacheDir, jarName, strUrl);
JarURLConnection jcl = (JarURLConnection) fetchUrl.toUri().toURL().openConnection();
Attributes attr = jcl.getMainAttributes();
String mainClass = (attr != null) ? attr.getValue(Attributes.Name.MAIN_CLASS) : null;
if (mainClass != null) {
// launch the program
}
}
private Path fetchUrl(Path cacheDir, String title, String strUrl) throws IOException {
Path cacheFile = cacheDir.resolve(title);
Path cacheFileDate = cacheDir.resolve(title + "_date");
URL url = new URL(strUrl);
URLConnection connection = url.openConnection();
if (Files.exists(cacheFile) && Files.exists(cacheFileDate)) {
String dateValue = Files.readAllLines(cacheFileDate).get(0);
connection.addRequestProperty("If-Modified-Since", dateValue);
String httpStatus = connection.getHeaderField(0);
if (httpStatus.indexOf(" 304 ") == -1) { // assuming that we get status 200 here instead
writeFiles(connection, cacheFile, cacheFileDate);
} else { // else not modified, so do not do anything, we return the cache file
System.out.println("Using cached file");
}
} else {
writeFiles(connection, cacheFile, cacheFileDate);
}
return cacheFile;
}
private void writeFiles(URLConnection connection, Path cacheFile, Path cacheFileDate) throws IOException {
System.out.println("Creating cache entry");
try (InputStream inputStream = connection.getInputStream()) {
Files.copy(inputStream, cacheFile, StandardCopyOption.REPLACE_EXISTING);
}
String lastModified = connection.getHeaderField("Last-Modified");
Files.write(cacheFileDate, lastModified.getBytes());
System.out.println(connection.getHeaderFields());
}
How can I save a jar file from a web server locally in a command-line program that exits and ONLY update that jar file when it has been changed on the server?
With JWS. It has an API so you can control it from your existing code. It already has versioning and caching, and comes with a JAR-serving servlet.
I have assumed that a .md5 file will be available both locally and at the web server. Same logic will apply if you wanted this to be a version control file.
The urls given in the following code need to updated according to your web server location and app context. Here is how your command line code would go
public class Main {
public static void main(String[] args) {
String jarPath = "/Users/nrj/Downloads/local/";
String jarfile = "apache-storm-0.9.3.tar.gz";
String md5File = jarfile + ".md5";
try {
// Update the URL to your real server location and application
// context
URL url = new URL(
"http://localhost:8090/JarServer/myjar?hash=md5&file="
+ URLEncoder.encode(jarfile, "UTF-8"));
BufferedReader in = new BufferedReader(new InputStreamReader(
url.openStream()));
// get the md5 value from server
String servermd5 = in.readLine();
in.close();
// Read the local md5 file
in = new BufferedReader(new FileReader(jarPath + md5File));
String localmd5 = in.readLine();
in.close();
// compare
if (null != servermd5 && null != localmd5
&& localmd5.trim().equals(servermd5.trim())) {
// TODO - Execute the existing jar
} else {
// Rename the old jar
if (!(new File(jarPath + jarfile).renameTo((new File(jarPath + jarfile
+ String.valueOf(System.currentTimeMillis())))))) {
System.err
.println("Unable to rename old jar file.. please check write access");
}
// Download the new jar
System.out
.println("New jar file found...downloading from server");
url = new URL(
"http://localhost:8090/JarServer/myjar?download=1&file="
+ URLEncoder.encode(jarfile, "UTF-8"));
// Code to download
byte[] buf;
int byteRead = 0;
BufferedOutputStream outStream = new BufferedOutputStream(
new FileOutputStream(jarPath + jarfile));
InputStream is = url.openConnection().getInputStream();
buf = new byte[10240];
while ((byteRead = is.read(buf)) != -1) {
outStream.write(buf, 0, byteRead);
}
outStream.close();
System.out.println("Downloaded Successfully.");
// Now update the md5 file with the new md5
BufferedWriter bw = new BufferedWriter(new FileWriter(md5File));
bw.write(servermd5);
bw.close();
// TODO - Execute the jar, its saved in the same path
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
And just in case you had control over the servlet code as well, this is how the servlet code goes:-
#WebServlet(name = "jarervlet", urlPatterns = { "/myjar" })
public class JarServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// Remember to have a '/' at the end, otherwise code will fail
private static final String PATH_TO_FILES = "/Users/nrj/Downloads/";
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String fileName = req.getParameter("file");
if (null != fileName) {
fileName = URLDecoder.decode(fileName, "UTF-8");
}
String hash = req.getParameter("hash");
if (null != hash && hash.equalsIgnoreCase("md5")) {
resp.getWriter().write(readMd5Hash(fileName));
return;
}
String download = req.getParameter("download");
if (null != download) {
InputStream fis = new FileInputStream(PATH_TO_FILES + fileName);
String mimeType = getServletContext().getMimeType(
PATH_TO_FILES + fileName);
resp.setContentType(mimeType != null ? mimeType
: "application/octet-stream");
resp.setContentLength((int) new File(PATH_TO_FILES + fileName)
.length());
resp.setHeader("Content-Disposition", "attachment; filename=\""
+ fileName + "\"");
ServletOutputStream os = resp.getOutputStream();
byte[] bufferData = new byte[10240];
int read = 0;
while ((read = fis.read(bufferData)) != -1) {
os.write(bufferData, 0, read);
}
os.close();
fis.close();
// Download finished
}
}
private String readMd5Hash(String fileName) {
// We are assuming there is a .md5 file present for each file
// so we read the hash file to return hash
try (BufferedReader br = new BufferedReader(new FileReader(
PATH_TO_FILES + fileName + ".md5"))) {
return br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
I can share experience of solving the same problem in our team. We have several desktop product written in java which are updated regularly.
Couple years ago we had separate update server for every product and following process of update: Client application has an updater wrapper that starts before main logic, and stored in a udpater.jar. Before start, application send request to update server with MD5-hash of application.jar file. Server compares received hash with the one that it has, and send new jar file to updater if hashes are different.
But after many cases, where we confused which build is now in production, and update-server failures we switched to continuous integration practice with TeamCity on top of it.
Every commit done by developer is now tracked by build server. After compilation and test passing build server assigns build number to application and shares app distribution in local network.
Update server now is a simple web server with special structure of static files:
$WEB_SERVER_HOME/
application-builds/
987/
988/
989/
libs/
app.jar
...
changes.txt <- files, that changed from last build
lastversion.txt <- last build number
Updater on client side requests lastversion.txt via HttpClient, retrieves last build number and compares it with client build number stored in manifest.mf.
If update is required, updater harvests all changes made since last update iterating over application-builds/$BUILD_NUM/changes.txt files. After that, updater downloads harvested list of files. There could be jar-files, config files, additional resources etc.
This scheme is seems complex for client updater, but in practice it is very clear and robust.
There is also a bash script that composes structure of files on updater server. Script request TeamCity every minute to get new builds and calculates diff between builds. We also upgrading now this solution to integrate with project management system (Redmine, Youtrack or Jira). The aim is to able product manager to mark build that are approved to be updated.
UPDATE.
I've moved our updater to github, check here: github.com/ancalled/simple-updater
Project contains updater-client on Java, server-side bash scripts (retrieves updates from build-server) and sample application to test updates on it.

Store and retrieve word documents with MySQL

I need to store and retrieve MS Word documents into MySQL 5.1 with Servlets. I've the code to upload a file, but I don't know can I feed into the table. I've used BLOB for the field I've to insert .doc files.
Here's my code snippet to upload files:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
// get access to file that is uploaded from client
Part p1 = request.getPart("file");
String type=p1.getContentType();
String name=p1.getName();
long size = p1.getSize();
InputStream is = p1.getInputStream();
//FileInputStream fis = is.
// read filename which is sent as a part
Part p2 = request.getPart("name");
Scanner s = new Scanner(p2.getInputStream());
String filename = s.nextLine(); // read filename from stream
// get filename to use on the server
String outputfile = this.getServletContext().getRealPath(filename); // get path on the server
FileOutputStream os = new FileOutputStream (outputfile);
// write bytes taken from uploaded file to target file
int ch = is.read();
while (ch != -1) {
os.write(ch);
ch = is.read();
}
os.close();
out.println("<h3>File : '" + name + "' Type : '" + type + "' "
+ "of Size : " + ((double) size/1024) + "KB uploaded successfully!</h3>");
}
catch(Exception ex) {
out.println("Exception -->" + ex.getMessage());
}
finally {
out.close();
}
}
Here, I've used Servlets 3.0 feature for uploading a file...
My table schema :
resources
- UserID [varchar(15)]
- Document [mediumblob]
Could anyone help me how can I store the document into the table and though BLOB is a type representing binary data, how can I retrieve as a Word Document (*.doc)?
I agree with Archimedix... Instead of putting them into MySQL as BLOB, you can store the file on the disk and store its path in MYSQL as TEXT field. This way your retrieval time will be low. If you are space conscious then you can zip the doc and save it on the disk and on request uncompress and send it.
UPDATE
From your code it appears that you already have the handle of the file and you are able to save it on the server.
Now to save space you can zip it using default java zip utility.
You might face a problem when two people upload two different files with the same name. To avoid scenarios like this you can either rename your archived document with an uuid (use java 6 uuid class) or you can generate SHA1 for that file and use that for name.
Now you can use the absolute path of the archived (and renamed file) for storing in the MySQL.
Instead of table schema
resources
UserID [varchar(15)]
Document [mediumblob]
You can use this
resources
UserID [varchar(15)]
Document [varchar(512)]
So for a query like this:
Select Document from table Documents WHERE UserID = 'abcd';
you will now get an absolute path for the zipped file. Uncompress this file and send it.
A partial answer on storing the Word documents in files:
You don't need any additional column to save the file name as the document's record ID can serve as the file name.
When saving a new document, do in a database transaction so that you can undo the process when something goes wrong.
In pseudo code, this would look like this:
begin transaction;
try {
save new record for document;
save Word document in predefined directory, using record's ID as the filename;
} catch (Exception e) {
rollback transaction;
throw e; // Rethrow exception
}
commit transaction;
The code above assumes that an exception is thrown when an error occurs.

Categories

Resources