/*
###############################################################################
# #
# Copyright (C) 2011-2016 OpenMEAP, Inc. #
# Credits to Jonathan Schang & Rob Thacher #
# #
# Released under the LGPLv3 #
# #
# OpenMEAP 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, either version 3 of the License, or #
# (at your option) any later version. #
# #
# OpenMEAP 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 OpenMEAP. If not, see <http://www.gnu.org/licenses/>. #
# #
###############################################################################
*/
package com.openmeap.android;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import android.app.Activity;
import android.content.Context;
import com.openmeap.thinclient.LocalStorage;
import com.openmeap.thinclient.LocalStorageException;
import com.openmeap.thinclient.update.UpdateException;
import com.openmeap.thinclient.update.UpdateResult;
import com.openmeap.thinclient.update.UpdateStatus;
import com.openmeap.util.GenericRuntimeException;
public class LocalStorageImpl implements LocalStorage {
private static String STORAGE_ROOT = "com.openmeap.storage";
private MainActivity activity = null;
public LocalStorageImpl(MainActivity activity) {
this.activity = activity;
}
/**
* Sets up a few system properties that are needed by the FileContentProvider
* I could probably put them in a better location, but this is adequate for the time being.
*/
public void setupSystemProperties() {
String path = activity.getFilesDir().getAbsolutePath()+System.getProperty("file.separator");
System.setProperty("root.openmeap.path",path);
String storageLocation = activity.getConfig().getStorageLocation();
System.setProperty("root.openmeap.internalStoragePrefix", storageLocation!=null ? storageLocation : "");
}
public Long getBytesFree() {
String absPath = activity.getFilesDir().getAbsolutePath();
android.os.StatFs fs = new android.os.StatFs(absPath);
Long blockSize = (long)fs.getBlockSize();
Long availableBlocks = (long)fs.getAvailableBlocks();
return blockSize * availableBlocks;
}
public void resetStorage() {
String currentPrefix = activity.getConfig().getStorageLocation();
if(currentPrefix!=null) {
resetStorage(currentPrefix);
activity.getConfig().clearStorageLocation();
}
}
/**
* Call this method remove the file.
* @param file: File object referrence.
*/
public void removeFile(File file) throws LocalStorageException {
try {
//Requesting the current file to delete.
file.delete();
} catch (Exception e) {
throw new LocalStorageException("LocalStorageImpl::removeFile()::Exception thrown while deleting the file.",e);
}
}
/**
* Call this method to traverse(Recursively) through directory and delete individual files.
* @param fileOrDirectory: file or directory referrence.
*/
public void traverseDirectoryChainAndRemove(File fileOrDirectory) throws LocalStorageException {
if (fileOrDirectory.exists()) {
if(fileOrDirectory.isDirectory()){
//means the fileOrDirectory is a directory.
if(fileOrDirectory.list().length!= 0){
//this directory has child files.
for( File file1 : fileOrDirectory.listFiles() ) {
traverseDirectoryChainAndRemove(file1);
}
}
//Requesting the current file to delete.
removeFile(fileOrDirectory);
}else {
//Requesting the current file to delete.
removeFile(fileOrDirectory);
}
}else {
//requested direcotory does not exist.
throw new LocalStorageException("LocalStorageImpl::traverseDirectoryChainAndRemove()::Directory does not exists.");
}
}
public void resetStorage(String prefix) {
try {
File fileOrDirectoryReferrence = new File(activity.getFilesDir(),prefix);
//actual call for removing the previous hash based webapp from phone memory.
traverseDirectoryChainAndRemove(fileOrDirectoryReferrence);
} catch (Exception e) {
;// handle reset storage failure.
}
}
public OutputStream openFileOutputStream(String fileName) throws LocalStorageException {
String internalStorageName = FileContentProvider.getInternalStorageFileName(fileName);
try {
return activity.openFileOutput(internalStorageName,Activity.MODE_PRIVATE);
} catch (FileNotFoundException e) {
throw new LocalStorageException(e);
}
}
public OutputStream openFileOutputStream(String prefix, String fileName) throws LocalStorageException {
String internalStorageName = FileContentProvider.getInternalStorageFileName(prefix,fileName);
try {
return activity.openFileOutput(internalStorageName,Activity.MODE_PRIVATE);
} catch (FileNotFoundException e) {
throw new LocalStorageException(e);
}
}
public void deleteImportArchive() {
activity.deleteFile("import.zip");
}
public OutputStream getImportArchiveOutputStream() throws LocalStorageException {
try {
return activity.openFileOutput("import.zip", Activity.MODE_PRIVATE);
} catch (FileNotFoundException e) {
throw new LocalStorageException(e);
}
}
public InputStream getImportArchiveInputStream() throws LocalStorageException {
try {
return activity.openFileInput("import.zip");
} catch (FileNotFoundException e) {
throw new LocalStorageException(e);
}
}
public void unzipImportArchive(UpdateStatus update) throws LocalStorageException {
// at this point, we've verified that:
// 1) we have enough space on the device
// 2) the archive downloaded is what was expected
ZipInputStream zis = null;
String newPrefix = "com.openmeap.storage."+update.getUpdateHeader().getHash().getValue();
File hashHolder = null;
String hashRootAbsolutePath = "";
try {
hashHolder = new File(activity.getFilesDir(),newPrefix);
hashHolder.mkdir();
hashRootAbsolutePath = hashHolder.getAbsolutePath();
} catch (Exception e) {
System.out.println("Exception thrown while creating hash folder.");
System.out.println(e);
}
try {
zis = new ZipInputStream( getImportArchiveInputStream() );
ZipEntry ze;
while ((ze = zis.getNextEntry()) != null) {
if( ze.isDirectory() ){
// continue;
try {
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println("Writing directory structure in phone memory.");
File directoryStructure = new File(hashRootAbsolutePath,ze.getName());
directoryStructure.mkdirs();
} catch (Exception e) {
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println("Exception thrown while writing directory structure.");
System.out.println(e);
}
}else {
try {
String osSeperator = System.getProperty("file.separator");
int seperatorLastIndex = ze.getName().lastIndexOf(osSeperator);
String fileName = ze.getName().substring(seperatorLastIndex+1, ze.getName().length());
String fileNameParentDirectoryPrefix = "";
String absolutePathFromPrefix = "";
if (seperatorLastIndex != -1 && seperatorLastIndex != 0) {
fileNameParentDirectoryPrefix = ze.getName().substring(0, seperatorLastIndex);
absolutePathFromPrefix = hashRootAbsolutePath+osSeperator+fileNameParentDirectoryPrefix;
} else {
absolutePathFromPrefix = hashRootAbsolutePath+osSeperator;
}
URI osResourePathForThisFile = URI.create(absolutePathFromPrefix);
File writableFileReference = new File(osResourePathForThisFile.getPath(),fileName);
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(writableFileReference.getAbsolutePath(),true),1024);
try {
byte[] buffer = new byte[1024];
int count;
while ((count = zis.read(buffer)) != -1) {
outputStream.write(buffer, 0, count);
}
}
catch( Exception e ) {
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println("Exception while writing file contents.");
System.out.println(e);
}
finally {
outputStream.close();
}
} catch (Exception e) {
System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
System.out.println("Unknown exception.");
System.out.println(e);
}
}
// Commenting following code to make use of file:/// alternate to content://
// OutputStream baos = openFileOutputStream(newPrefix,ze.getName());
// try {
// byte[] buffer = new byte[1024];
// int count;
// while ((count = zis.read(buffer)) != -1) {
// baos.write(buffer, 0, count);
// }
// }
// catch( Exception e ) {
// ;// TODO: something, for the love of god.
// }
// finally {
// baos.close();
// }
}
} catch( Exception e ) {
// delete the recently unzipped assets
throw new LocalStorageException(e);
} finally {
if( zis!=null ) {
try {
zis.close();
} catch (IOException e) {
throw new GenericRuntimeException(e);
}
}
}
}
public void closeOutputStream(OutputStream outputStream) throws LocalStorageException {
try {
if(outputStream==null) {
return;
}
outputStream.close();
} catch(IOException ioe) {
throw new LocalStorageException(ioe);
}
}
public void closeInputStream(InputStream inputStream) throws LocalStorageException {
try {
if(inputStream==null) {
return;
}
inputStream.close();
} catch(IOException ioe) {
throw new LocalStorageException(ioe);
}
}
public String getStorageRoot() {
return STORAGE_ROOT+".";
}
}