/**
*
* @author greg (at) myrobotlab.org
*
* This file is part of MyRobotLab (http://myrobotlab.org).
*
* MyRobotLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version (subject to the "Classpath" exception
* as provided in the LICENSE.txt file that accompanied this code).
*
* MyRobotLab is distributed in the hope that it will be useful or fun,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* All libraries in thirdParty bundle are subject to their own license
* requirements - please refer to http://myrobotlab.org/libraries for
* details.
*
* Enjoy !
*
* */
package org.myrobotlab.io;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipException;
import org.myrobotlab.cmdline.CmdLine;
import org.myrobotlab.logging.Level;
import org.myrobotlab.logging.LoggerFactory;
import org.myrobotlab.logging.Logging;
import org.myrobotlab.logging.LoggingFactory;
import org.slf4j.Logger;
/**
* class of useful utility functions we do not use nio - for portability reasons
* e.g. Android
*
* @author GroG
*
*/
public class FileIO {
public static class FileComparisonException extends Exception {
private static final long serialVersionUID = 1L;
public FileComparisonException(String msg) {
super(msg);
}
}
static public final Logger log = LoggerFactory.getLogger(FileIO.class);
/**
* compares two files - throws if they are not identical, good to use in
* testing
*
* @param filename1
* @param filename2
* @throws FileComparisonException
* @throws IOException
*/
static public final boolean compareFiles(String filename1, String filename2) throws FileComparisonException, IOException {
File file1 = new File(filename1);
File file2 = new File(filename2);
if (file1.length() != file2.length()) {
throw new FileComparisonException(String.format("%s size is %d adn %s is size %d", filename1, file1.length(), filename2, file2.length()));
}
byte[] a1 = toByteArray(new File(filename1));
byte[] a2 = toByteArray(new File(filename2));
for (int i = 0; i < a1.length; ++i) {
if (a1[i] != a2[i]) {
throw new FileComparisonException(String.format("files differ at position %d", i));
}
}
return true;
}
/**
* a simple copy method which works like a 'regular' operating system copy
*
* @param src
* @param dst
* @throws IOException
*/
// TODO - test dst exists or not
// TODO - test slashes on end of dirs
static public final void copy(File src, File dst) throws IOException {
log.info("copying from {} to {}", src, dst);
if (!src.isDirectory()) {
byte[] b = toByteArray(src);
toFile(dst, b);
} else {
if (!dst.exists()) {
// if dst does not exist copy 'contents' of src into dst
dst.mkdirs();
log.info("directory copied from {} to {}", src, dst);
String files[] = src.list();
for (String file : files) {
File srcFile = new File(src, file);
File destFile = new File(dst, file);
copy(srcFile, destFile);
}
} else {
// when dst exists - then whole directory src is copied into dst
copy(src, new File(gluePaths(dst.getPath(), src.getName())));
}
}
}
/**
* copy file or folder from one place to another with string interface
*
* @param src
* @param dst
* @throws IOException
*/
static public final void copy(String src, String dst) throws IOException {
copy(new File(src), new File(dst));
}
static public final boolean extract(String src, String dst) throws IOException {
return extract(getRoot(), src, dst);
}
/**
* extract needs 3 parameters - a root file source, which could be a file
* directory or jar file, a src location, and a destination. During runtime
* this method will extract contents from a jar specified, during build time
* it will copy from a folder location. It could probably be improved, and
* simplified to take only 2 parameters, but that would mean calling methods
* would need to be 'smart' enough to use full getURI notation .. e.g.
* jar:file:/C:/proj/parser/jar/parser.jar!/test.xml
*
* e.g
* http://stackoverflow.com/questions/402683/how-do-i-get-just-the-jar-url-
* from-a-jar-url-containing-a-and-a-specific-fi/402771#402771 final URL
* jarUrl = new URL("jar:file:/C:/proj/parser/jar/parser.jar!/test.xml");
* final JarURLConnection connection = (JarURLConnection)
* jarUrl.openConnection(); final URL url = connection.getJarFileURL();
*
*
* @param root
* - the jar file / or absolute file location .. e.g.
* file:/c:/somedir/myrobotlab.jar or file:/c:/somdir/bin
* @param src
* - the folder or file to extract from the root
* @param dst
* - target location
* @return
* @throws IOException
*/
static public final boolean extract(String root, String src, String dst) throws IOException {
log.info("extract([{}], [{}], [{}])", root, src, dst);
boolean contents = false;
boolean found = false;
boolean firstMatch = true;
// === pre-processing / normalizing of paths begin ===
if (dst == null || dst.equals("") || dst.equals("./")) {
dst = ".";
}
if (src == null || src.equals("") || src.equals("./")) {
src = ".";
}
// normalize slash
src = src.replace("\\", "\\\\");
dst = dst.replace("\\", "\\\\");
// normalize [from | from/ | from/*]
String fromRoot = null;
if (src != null && (src.endsWith("/") || src.endsWith("/*"))) {
fromRoot = src.substring(0, src.lastIndexOf("/"));
contents = true;
} else {
fromRoot = src;
}
// extract(/C:/mrl/myrobotlab/dist/myrobotlab.jar, resource, )
log.info("normalized extract([{}], [{}], [{}])", root, src, dst);
// === pre-processing / normalizing of paths end ===
// FIXME - isJar(root)
if (isJar(root)) {
// String jarFile = getJarName();
// if an exact file (not directory) is specified
// we can immediately extract it
// however for directories - there is no specific key given
// and all the contents has to be iterated through :P
// trying direct key of resource first ....
URL url = FileIO.class.getResource(src);
if (url != null) {
log.info("{} exists on the classpath - extracting to {}", url, dst);
FileIO.toFile(dst, toByteArray(FileIO.class.getResourceAsStream(src)));
return true;
}
log.info("extracting from {}", root);
JarFile jar = new JarFile(root);
Enumeration<JarEntry> enumEntries = jar.entries();
// jar access is non-recursive
while (enumEntries.hasMoreElements()) {
JarEntry file = (JarEntry) enumEntries.nextElement();
// log.debug(file.getName());
// spin through resrouces until a match
if (fromRoot != null && !file.getName().startsWith(fromRoot)) {
// log.info(String.format("skipping %s", file.getName()));
continue;
}
found = true;
// our first match !
if (!file.isDirectory()) {
// not a directory
String name = null;
if (contents) {
name = String.format("%s/%s", dst, file.getName().substring((fromRoot.length() + 1)));
} else {
if (firstMatch) {
// file to file
name = dst;
} else {
// dirFile to file
name = String.format("%s/%s", dst, file.getName());
}
}
log.info("extracting {} to {}", file.getName(), name);
// FIXING toFile(filename, data);
// FIXING toByteArray(is)
FileIO.toFile(name, toByteArray(jar.getInputStream(file)));
// file to file copy ... done
if (firstMatch) {
break;
}
} else {
// df
// if (conti)
String name = null;
if (contents) {
name = String.format("%s/%s", dst, file.getName().substring((fromRoot.length() + 1)));
} else {
name = String.format("%s/%s", dst, file.getName());
}
File d = new File(name);
d.mkdirs();
}
firstMatch = false;
}
if (!found) {
log.error("could not find {}", src);
}
jar.close();
return found;
} else {
copy(new File(String.format("%s/%s", root, src)), new File(dst));
return true;
}
}
/**
* copies a resource file or directory from the myrobotlab.jar and extracts it
* onto the file system at a destination supplied. This method works during
* dev, build, and runtime
*
* @param src
* @param dst
* @return
* @throws IOException
*/
static public final void extractResource(String src, String dst) throws IOException {
extract(getRoot(), gluePaths("/resource/", src), dst);
}
/**
* extractResources will extract the entire /resource directory out unless it
* already exist
*
* this process is important to the webgui, as it accesses the AngularJS files
* from the file system and not within the jar
*
* @return
*/
static public final boolean extractResources() {
try {
return extractResources(false);
} catch (Exception e) {
Logging.logError(e);
}
return false;
}
/**
* same as extractResources except with an ability to force overwriting an
* already existing directory
*
* @param overwrite
* @return
* @throws IOException
*/
static public final boolean extractResources(boolean overwrite) throws IOException {
String resourceName = "resource";
File check = new File(resourceName);
if (check.exists() && !overwrite) {
log.warn("{} aleady exists - not extracting", resourceName);
return false;
}
if (!isJar() && !overwrite) {
log.warn("mrl is not operating in a jar - not extracting");
return false;
}
return extract(resourceName, null);
}
/**
* get configuration directory
*
* @return
*/
static public final String getCfgDir() {
try {
String dirName = String.format("%s%s.myrobotlab", System.getProperty("user.dir"), File.separator);
File dir = new File(dirName);
if (!dir.exists()) {
boolean ret = dir.mkdirs();
if (!ret) {
log.error("could not create {}", dirName);
}
}
if (!dir.isDirectory()) {
log.error("{} is not a file", dirName);
}
return dirName;
} catch (Exception e) {
Logging.logError(e);
}
return null;
}
/**
* Method to universally get the root location of where mrl is currently
* running form. It could be from Eclipse's bin directory, a build directory,
* or inside a jar.
*
* There are 100 rabbit holes, with the different ways you can 'attempt' to
* get a path to where mrl is running. Some work during Develop-Time, and
* return null during Runtime. Some encode or decode the path into something
* which can not be used. Some appear simple superficially. This currently is
* the best pratical solution I have found.
*
* 2 Step process: 1. get URL of code executing 2. convert to a File
*
* Test Results:
*
* == Develop-Time Windows Eclipse == [/C:/mrlDevelop/myrobotlab/bin/]
*
* == Run-Time Windows Jar == [/C:/mrl.test/current
* 10/develop/myrobotlab.1.0.${env.TRAVIS_BUILD_NUMBER}.jar]
*
* http://stackoverflow.com/questions/9729197/getting-current-class-name-
* including-package
* https://community.oracle.com/blogs/kohsuke/2007/04/25/how-convert-
* javaneturl-javaiofile
*
* @return
*/
static public final String getRoot() {
try {
String source = FileIO.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
log.debug("getRoot {}", source);
return source;
} catch (Exception e) {
log.error("getRoot threw");
Logging.logError(e);
return null;
}
}
static public final List<String> getServiceList() throws IOException {
List<URL> urls = listContents(getRoot(), "org/myrobotlab/service", false, new String[] { ".*\\.class" }, new String[] { ".*Test\\.class", ".*\\$.*" });
ArrayList<String> classes = new ArrayList<String>();
log.info("found {} service files in {}", urls.size(), getRoot());
// String path = packageName.replace('.', '/');
for (URL url : urls) {
String urlName = url.getPath();
String simpleName = urlName.substring(urlName.lastIndexOf("/") + 1, urlName.lastIndexOf("."));
String classname = String.format("org.myrobotlab.service.%s", simpleName);
classes.add(classname);
}
return classes;
}
static public final String gluePaths(String path1, String path2) {
// normalize to 'real' network slash direction ;)
// jar internals probably do not handle back-slash
// most file access even on 'windows' machine can interface correctly
// with forward slash
// network url order is always forward slash
path1 = path1.replace("\\", "/");
path2 = path2.replace("\\", "/");
// only 1 slash between path1 & path2
if (path1.endsWith("/")) {
path1 = path1.substring(0, path1.length() - 1);
}
if (path2.startsWith("/")) {
path2 = path2.substring(1);
}
return String.format("%s/%s", path1, path2);
}
static public final boolean isJar() {
return isJar(null);
}
static public final boolean isJar(String path) {
if (path == null) {
path = getRoot();
}
if (path != null) {
return path.endsWith(".jar");
}
return false;
}
/*
* FIXME FIXME - make this a more general implementation of getServiceList
* static public final List<File> getPackageContent(String packageName) throws
* IOException { return getPackageContent(packageName, false, null, null); }
*/
/**
* The "goal" of this method is to get the list of contents from a package
* REGARDLESS of the packaging :P Regrettably, the implementation depends
* greatly on if the classes are on the file system vs if they are in a jar
* file
*
* Step 1: find out if our application is running in a jar (runtime release)
* or running on classes on the file system (debug)
*
* Step 2: if we are running from the file system with .class files - it
* becomes very simple file operations
*
* @param packageName
* @param recurse
* @param include
* @param exclude
* @return
* @throws IOException
*/
// FIXME reconcile with listPackage - No Files ! use URL returns ?!?!?
/*
* static public final List<File> getPackageContent(String packageName,
* boolean recurse, String[] include, String[] exclude) throws IOException {
*
* ArrayList<File> files = new ArrayList<File>();
*
* if (!isJar()) {
*
* ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
* assert classLoader != null; String path = packageName.replace('.', '/');
* Enumeration<URL> resources = classLoader.getResources(path); List<File>
* dirs = new ArrayList<File>(); log.info("resources.hasMoreElements {}",
* resources.hasMoreElements());
*
* while (resources.hasMoreElements()) { URL resource =
* resources.nextElement(); log.info("resources.nextElement {}", resource);
* dirs.add(new File(resource.getFile())); }
*
* // if (recurse) { for (File directory : dirs) { // FIXME
* files.addAll(findPackageContents(directory, // packageName, recurse,
* include, exclude)); } } else { // sdf }
*
* // } return files;// .toArray(new Class[classes.size()]); }
*/
/*
* public static String getJarName() { String nm = getRoot(); if
* (!nm.endsWith(".jar")) { log.error("mrl is not in a jar!"); return null; }
* return nm; }
*/
/**
* list the contents of 'self' at directory 'src'
*
* @param src
* @return
* @throws IOException
*/
static public final List<URL> listContents(String src) throws IOException {
return listContents(getRoot(), src, true, null, null);
}
static public final List<URL> listContents(String root, String src) throws IOException {
return listContents(root, src, true, null, null);
}
/**
* list the contents of a file system directory or list the contents of a jar
* file directory
*
*
* @param root
* @param src
* @param recurse
* @param include
* @param exclude
* @return
* @throws IOException
*/
static public final List<URL> listContents(String root, String src, boolean recurse, String[] include, String[] exclude) throws IOException {
List<URL> classes = new ArrayList<URL>();
log.info("findPackageContents root [{}], src [{}], recurse [{}], include [{}], exclude [{}]", root, src, recurse, Arrays.toString(include), Arrays.toString(exclude));
if (root == null) {
root = "./";
}
if (!isJar(root)) {
String rootPath = gluePaths(root, src);
File srcFile = new File(rootPath);
if (!srcFile.exists()) {
log.error("{} does not exist");
return classes;
}
// MUST BE DIRECTORY !
if (!srcFile.isDirectory()) {
log.error("{} is not a directory");
return classes;
}
File[] files = srcFile.listFiles();
for (File file : files) {
if (file.isDirectory() && recurse) {
assert !file.getName().contains(".");
classes.addAll(listContents(rootPath, "/" + file.getName(), recurse, include, exclude));
} else { // if (file.getName().endsWith(".class")) {
String filename = file.getName();
boolean add = false;
if (include != null) {
for (int i = 0; i < include.length; ++i) {
if (filename.matches(include[i])) {
add = true;
break;
}
}
}
if (exclude != null) {
for (int i = 0; i < exclude.length; ++i) {
if (filename.matches(exclude[i])) {
add = false;
break;
}
}
}
if (include == null && exclude == null) {
add = true;
}
if (add) {
// IMPORTANT toURI().toURL() otherwise spaces can be
// problems
classes.add(file.toURI().toURL());
}
}
}
} else {
///////////////////////////////////////////////////////////////////////////////////////////////
// FIXME - location of file will be different from path inside
// local file
// url=new URL("jar:file:/C:/dist/current/develop/myrobotlab.jar!/"
// remote file
// url=new
// URL("jar:http://mrl-bucket-01.s3.amazonaws.com/current/develop/myrobotlab.jar!/");
// URLcon=(JarURLConnection)(url.openConnection());
// jar=URLcon.getJarFile();
JarFile jar = new JarFile(root);
Enumeration<JarEntry> enumEntries = jar.entries();
/**
* jar access requires a linear spin through all the entries :( and
* unfortunately the paths are not ordered as a depth first ordering,
* instead they are breadth first, so a 'group of files' in a 'directory'
* can not be optimized in access - you are required to look through 'all'
* entries because there is no order guarantee you will find them all in
* one spot
*/
while (enumEntries.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) enumEntries.nextElement();
// search for matching entries
if (!jarEntry.getName().startsWith(src)) {
// log.info(String.format("skipping %s", file.getName()));
continue;
}
String urlStr = String.format("jar:file:%s!/%s", root, jarEntry.getName());
if (jarEntry.isDirectory()) {
log.info("match on directory url {}", urlStr);
} else {
log.info("adding url {}", urlStr);
URL url = new URL(urlStr);
classes.add(url);
}
}
jar.close();
}
return classes;
}
static public final List<File> listResourceContents(String path) throws IOException {
List<URL> urls = null;
String root = (path.startsWith("/")) ? "resource" : "resource/";
urls = listContents(root + path);
return UrlsToFiles(urls);
}
/**
* inter process file communication - default is to wait and attempt to load a
* file in the next second - it comes from savePartFile - then the writing of
* the file from a different process should be an atomic move regardless of
* file size
*
* @param filename
* @throws IOException
*/
static public final byte[] loadPartFile(String filename) throws IOException {
return loadPartFile(filename, 1000);
}
static public final byte[] loadPartFile(String filename, long timeoutMs) throws IOException {
long startTs = System.currentTimeMillis();
try {
while (System.currentTimeMillis() - startTs < timeoutMs) {
File file = new File(filename);
if (file.exists()) {
return toByteArray(file);
}
Thread.sleep(30);
}
} catch (Exception e) {
new IOException("interrupted while waiting for file to arrive");
}
return null;
}
// FIXME - UNIT TESTS !!!
public static void main(String[] args) throws ZipException, IOException {
// foo://example.com:8042/over/there?name=ferret#nose
// \_/ \______________/\_________/ \_________/ \__/
// | | | | |
// scheme authority path query fragment
// File f = new File(uri.getPath()); - handle depending on scheme?
LoggingFactory.init(Level.INFO);
FileIO.extract("/C:/mrl.test/current/myrobotlab.jar", "/resource/framework/serviceData.json", "C:\\mrl.test\\current\\.myrobotlab\\serviceData.json");
copy("dir1", "dir2");
// JUNIT BEGIN
String result = gluePaths("/", "/a/");
// assert /a/
result = gluePaths("/a/", "\\b\\");
// assert /a/b/
log.info(result);
result = gluePaths("/a", "\\b\\");
// assert /a/b/
result = gluePaths("\\a\\", "\\b\\");
// assert /a/b/
result = gluePaths("\\a\\", "b\\");
// assert /a/b/
/*
* URI ?? full circle URL url = new
* URL("jar:file:/C:/Program%20Files/test.jar!/foo/bar"); JarURLConnection
* connection = (JarURLConnection) url.openConnection(); File file = new
* File(connection.getJarFileURL().toURI())
*
* getResource ! takes string - returns url URL url =
* FileIO.class.getResource("/com"); =>
* jar:file:/C:/mrlDevelop/repo/org.alicebot.ab/0.0.6.26/Ab.jar!/com
*
*
*/
try {
// TODO - matrix of all file listing / url listings
// TODO - test getRoot with spaces and utf-8
// file:/C url string paths
// file:jar:/mrlDevelop/dist
// TODO - various other url path combos
// TODO - make a jar - test it
CmdLine cmdLine = new CmdLine(args);
log.info("=== jar info begin ===");
log.info("source url [{}]", FileIO.class.getProtectionDomain().getCodeSource().getLocation());
log.info("source uri [{}]", FileIO.class.getProtectionDomain().getCodeSource().getLocation().toURI());
log.info("source path [{}]", FileIO.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
log.info("=== jar info end ===");
log.info("getRoot [{}]", getRoot());
// interesting result ! - multiple definitions across many
// jars are handled with this classloader's 'first jar match'
URL url = FileIO.class.getResource("/com");
log.info("{}", url);
// File test = new File(url.toURI());
// log.info("{}", test.exists());
// File test = new File("/C:/")
// === jar info begin ===
// source url
// [file:/C:/mrlDevelop/myrobotlab/dist/current/develop/myrobotlab.jar]
// source uri
// [file:/C:/mrlDevelop/myrobotlab/dist/current/develop/myrobotlab.jar]
// source path
// [/C:/mrlDevelop/myrobotlab/dist/current/develop/myrobotlab.jar]
// === jar info end ===
// getRoot
// [/C:/mrlDevelop/myrobotlab/dist/current/develop/myrobotlab.jar]
// file:/c:/windows exists true
// file:///c:/windows exists true
//
//
// final URL jarUrl = new
// URL("jar:file:/C:/proj/parser/jar/parser.jar!/test.xml");
// final JarURLConnection connection = (JarURLConnection)
// jarUrl.openConnection();
// final URL url = connection.getJarFileURL();
//
// System.out.println(url.getFile());
//
List<String> services = getServiceList();
log.info("{}", services.size());
URI uri = new URI("file:/c:/windows");
File f = new File(uri);
log.info("{} exists {}", uri, f.exists());
// uri = new URI("file://c:/windows");
// f = new File(uri);
// log.info("{} exists {}", uri, f.exists());
// throws - java.lang.IllegalArgumentException: URI has an authority
// component
uri = new URI("file:///c:/windows");
f = new File(uri);
log.info("{} exists {}", uri, f.exists());
/*
* URI uri = new URI("file://c:/windows"); File f = new File(uri);
* log.info("{} exists {}", uri, f.exists());
*/
// info part
// test examples root - . ./ / <-- absolute
String root = cmdLine.getSafeArgument("-root", 0, "dist/current/develop/myrobotlab.jar");
String src = cmdLine.getSafeArgument("-src", 0, "resource/Python/examples");
String dst = cmdLine.getSafeArgument("-dst", 0, "test2");
log.info("dst arg: {}", dst);
//
List<File> files = listResourceContents("Python/examples");
log.info("listInternalContents /Python/examples size {}", files.size());
List<URL> urls = null;
log.info("findPackageContents resource/Python/examples");
urls = listContents(root, "resource/Python/examples");
log.info("findPackageContents resource/Python/examples {}", urls.size());
/*
* for (int i = 0; i < urls.size(); ++i) { File test = new
* File(urls.get(i).getPath()); String x = FileIO.toString(test);
* log.info("{}", test); }
*/
urls = listContents(getRoot(), "resource/Python/examples");
log.info("findPackageContents resource/Python/examples {}", urls.size());
urls = listContents(src);
log.info("findPackageContents {} {}", src, urls.size());
urls = listContents(root, "org/myrobotlab/service");
// urls = getPackageContent("org.myrobotlab.service");
// log.info("listResourceContents {} {}", src, urls.size());
// DOOD ! - listResourceContents findPackagContent getPackageContent
// copy requirements
// FIXME - don't use package names for consistency - these are all
// file manipulations - use file notation
// deravations for root="/c:/.../bin/ or /c:/.../myrobotlab.jar!"
// extract root="/c:/.../bin or /c:/.../myrobotlab.jar" src="/ or /*
// or blank or null or ./" dst="/ or /* or blank or null or ./"
// the contents of (bin or myrobotlab.jar) will be extracted in the
// current directory
// root bounds test .. root="/" src="/" dst="?"
// more testing spaces, special characters, UTF-8
// log.info("extract test");
// extractResources(true);
// extract(src, dst);
// inJar
// extract ("/resource", "test"); -> .\bin\resource\Python\examples
// does not exist what the hell?
// extract(/C:/mrlDevelop/myrobotlab/dist/current/develop/myrobotlab.jar,
// /, test)
/*
* final URL jarUrl = new
* URL("jar:file:/C:/mrl/myrobotlab/dist/myrobotlab.jar!/resource"); final
* JarURLConnection connection = (JarURLConnection)
* jarUrl.openConnection(); final URL url = connection.getJarFileURL();
*
* System.out.println(url.getFile());
*/
log.info("isJar : {}", isJar());
// File[] files = getPackageContent("org.myrobotlab.service");
// extract("develop/myrobotlab.jar", "resource/version.txt",
// "./version.txt");
// extract("/C:/mrl/myrobotlab/dist/myrobotlab.jar", "resource",
// "");
// extract("dist/myrobotlab.jar", "resource", "");
// extractResources();
/*
* // extract directory to a non existent directory // result should be
* test7 extract("dist/myrobotlab.jar", "resource/AdafruitMotorShield/*",
* "test66");
*
* // file to file extract("dist/myrobotlab.jar", "module.properties",
* "module.txt");
*
* // file to file extract("dist/myrobotlab.jar",
* "resource/ACEduinoMotorShield.png", "ACEduinoMotorShield.png");
*
* // file to file extract("dist/myrobotlab.jar",
* "resource/ACEduinoMotorShield.png",
* "test2/deeper/ACEduinoMotorShield.png");
*
* // extract directory to a non existent directory // result should be
* test7 extract("dist/myrobotlab.jar", "resource/*", "test7");
*
* // extract directory to a non existent directory // result should be
* test8/testdeeper/(contents of resource) extract("dist/myrobotlab.jar",
* "resource/", "test8/testdeeper");
*
* // extract directory to a non existent directory // result should be
* test3/deep/deeper/resource extract("dist/myrobotlab.jar", "resource",
* "test3/deep/deeper");
*
* String t = "this is a test"; FileIO.savePartFile("save.txt",
* t.getBytes()); byte[] data = FileIO.loadPartFile("save.txt", 10000); if
* (data != null) { log.info(new String(data)); }
*/
/*
* String data = resourceToString("version.txt"); data =
* resourceToString("framework/ivychain.xml"); data =
* resourceToString("framework/serviceData.xml");
*
* byte[] ba = resourceToByteArray("version.txt"); ba =
* resourceToByteArray("framework/version.txt"); ba =
* resourceToByteArray("framework/serviceData.xml");
*
* String hello = resourceToString("blah.txt");
*
* copyResource("mrl_logo.jpg", "mrl_logo.jpg");
*
* byte[] b = resourceToByteArray("mrl_logo.jpg");
*
* File[] files = getPackageContent("");
*
* log.info(getBinaryPath());
*
* log.info("{}", b);
*
* log.info("done");
*/
} catch (Exception e) {
Logging.logError(e);
}
}
/**
* resource directory resource contents read into a byte array
*
* @param src
* - location - (root is /resource) - e.g. src =
* Python/examples/someFile.py
* @return
*/
static public final byte[] resourceToByteArray(String src) {
String filename = String.format(gluePaths("/resource/", src));
log.info(String.format("looking for %s", filename));
InputStream isr = null;
if (isJar()) {
isr = FileIO.class.getResourceAsStream(filename);
} else {
try {
isr = new FileInputStream(String.format("%sresource/%s", getRoot(), src));
} catch (Exception e) {
Logging.logError(e);
return null;
}
}
byte[] data = null;
try {
if (isr == null) {
log.error(String.format("can not find resource [%s]", filename));
return null;
}
data = toByteArray(isr);
} finally {
try {
if (isr != null) {
isr.close();
}
} catch (Exception e) {
}
}
return data;
}
/**
* resource directory resource contents read into a string
*
* @param src
* - location - (root is /resource) - e.g. src =
* Python/examples/someFile.py
* @return
*/
static public final String resourceToString(String src) {
byte[] bytes = resourceToByteArray(src);
if (bytes == null) {
return null;
}
return new String(bytes);
}
/**
* removes a file or recursively removes directory
*
* @param file
* @return
*/
static public final boolean rm(File file) {
if (file.isDirectory())
return rmDir(file, null);
else {
log.info("removing file {}", file.getAbsolutePath());
return file.delete();
}
}
/**
* removes a file or recursively removes directory
*
* @param filename
* @return
*/
static public final boolean rm(String filename) {
return rm(new File(filename));
}
/**
* recursively remove files and directories, leaving exlusions
*
* @param directory
* - the directory to remove
* @param exclude
* - the exceptions to save
* @return
*/
static public final boolean rmDir(File directory, Set<File> exclude) {
if (directory.exists()) {
File[] files = directory.listFiles();
if (null != files) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
rmDir(files[i], exclude);
} else {
if (exclude != null && exclude.contains(files[i])) {
log.info("skipping exluded file {}", files[i].getName());
} else {
log.info("removing file - {}", files[i].getAbsolutePath());
files[i].delete();
}
}
}
}
}
boolean ret = (exclude != null) ? true : (directory.delete());
return ret;
}
/**
* for intra-process file writing & locking ..
*
* @param filename
* @param data
* @throws IOException
*/
static public final void savePartFile(File file, byte[] data) throws IOException {
// first delete any part or filename file currently there
String filename = file.getName();
if (file.exists()) {
if (!file.delete()) {
throw new IOException(String.format("%s exists but could not delete", filename));
}
}
String partFilename = String.format("%s.part", filename);
File partFile = new File(partFilename);
if (partFile.exists()) {
if (!partFile.delete()) {
throw new IOException(String.format("%s exists but could not delete", partFilename));
}
}
toFile(new File(partFilename), data);
if (!partFile.renameTo(new File(filename))) {
throw new IOException(String.format("could not rename %s to %s .. don't know why.. :(", partFilename, filename));
}
}
/**
* simple file to byte array
*
* @param file
* - file to read
* @return byte array of contents
* @throws IOException
*/
static public final byte[] toByteArray(File file) throws IOException {
FileInputStream fis = null;
byte[] data = null;
fis = new FileInputStream(file);
data = toByteArray(fis);
fis.close();
return data;
}
/**
* IntputStream to byte array
*
* @param is
* @return
*/
static public final byte[] toByteArray(InputStream is) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
int nRead;
byte[] data = new byte[16384];
while ((nRead = is.read(data, 0, data.length)) != -1) {
baos.write(data, 0, nRead);
}
baos.flush();
baos.close();
return baos.toByteArray();
} catch (Exception e) {
Logging.logError(e);
}
return null;
}
static public void toFile(File dst, byte[] data) throws IOException {
FileOutputStream fos = null;
fos = new FileOutputStream(dst);
fos.write(data);
fos.close();
}
static public void toFile(String dst, byte[] data) throws IOException {
toFile(new File(dst), data);
}
/**
* String to file
*
* @param filename
* - new file name
* @param data
* - string data to save
* @throws IOException
*/
static public final void toFile(String filename, String data) throws IOException {
toFile(new File(filename), data.getBytes());
}
static public final String toString(File file) throws IOException {
byte[] bytes = toByteArray(file);
if (bytes == null) {
return null;
}
return new String(bytes);
}
static public final String toString(String filename) throws IOException {
return toString(new File(filename));
}
static public final List<File> UrlsToFiles(List<URL> urls) {
List<File> files = new ArrayList<File>();
for (int i = 0; i < urls.size(); ++i) {
files.add(new File(urls.get(i).getPath()));
}
return files;
}
public void zip(String filename, List<File> files) throws IOException {
zip(filename, files);
}
public void zip(String filename, List<File> files, String version) throws IOException {
if (version == null) {
version = "1.0";
}
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, version);
JarOutputStream jar = new JarOutputStream(new FileOutputStream(filename), manifest);
for (int i = 0; i < files.size(); ++i) {
zipAdd(jar, new File("inputDirectory"));
}
jar.close();
}
public void zipAdd(JarOutputStream jar, File src) throws IOException {
BufferedInputStream in = null;
try {
if (src.isDirectory()) {
String name = src.getPath().replace("\\", "/");
if (!name.isEmpty()) {
if (!name.endsWith("/"))
name += "/";
JarEntry entry = new JarEntry(name);
entry.setTime(src.lastModified());
jar.putNextEntry(entry);
jar.closeEntry();
}
for (File nestedFile : src.listFiles())
zipAdd(jar, nestedFile);
return;
}
JarEntry entry = new JarEntry(src.getPath().replace("\\", "/"));
entry.setTime(src.lastModified());
jar.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(src));
byte[] buffer = new byte[1024];
while (true) {
int count = in.read(buffer);
if (count == -1)
break;
jar.write(buffer, 0, count);
}
jar.closeEntry();
} finally {
if (in != null)
in.close();
}
}
public static Properties loadProperties(String propertiesFile) throws IOException {
Properties props = new Properties();
InputStream in = new FileInputStream(propertiesFile);
props.load(in);
in.close();
return props;
}
public static HashMap<String, String> loadPropertiesAsMap(String propertiesFile) throws IOException {
Properties props = FileIO.loadProperties(propertiesFile);
HashMap<String, String> propMap = new HashMap<String, String>();
for (Object key : props.keySet()) {
propMap.put(key.toString(), props.getProperty(key.toString()));
}
return propMap;
}
}