/**
*
*/
package ma.car.tishadow.bundle.update.util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Represents an utility to manipulate bundle manifest.
* @author wei.ding
*/
public final class ManifestUtil {
public static class PatchInfo {
private List<String> filesToDelete;
private List<String> filesToAdd;
private List<String> filesToUpdate;
public PatchInfo() {
super();
this.filesToAdd = new ArrayList<String>();
this.filesToUpdate = new ArrayList<String>();
this.filesToDelete = new ArrayList<String>();
}
public List<String> getFilesToAdd() {
return filesToAdd;
}
public List<String> getFilesToDelete() {
return filesToDelete;
}
public List<String> getFilesToUpdate() {
return filesToUpdate;
}
public boolean isEmpty() {
return this.filesToAdd.isEmpty() && this.filesToUpdate.isEmpty() && this.filesToDelete.isEmpty();
}
}
/**
* Filename of manifest file.
*/
public static final String MANIFEST_FILENAME = "manifest.mf";
private static final String COLUMN_SYM = ",";
private static final String COMMENT_SYM = "#";
private static final String BUNDLE_VERSION_REGEXP = "[^\\d]";
private static final String BUNDLE_VERSION_HEAD_PATTERN = "^" + COMMENT_SYM + "Created:[\\d]+$";
private static final String FORCE_UPDATE_SIGN_HEAD_PATTERN = COMMENT_SYM + "ForceUpdate:";
/**
* Compare two manifests, and return the differences.
* @param oldManifest
* @param newManifest
* @return
* @throws IOException
*/
public static PatchInfo compareManifest(File oldManifest, File newManifest) throws IOException {
Map<String, String> oldManifestMap = translate(oldManifest);
Map<String, String> newManifestMap = translate(newManifest);
PatchInfo patch = new PatchInfo();
for (Map.Entry<String, String> entry : newManifestMap.entrySet()) {
if (!oldManifestMap.containsKey(entry.getKey())) {
patch.getFilesToAdd().add(entry.getKey());
} else {
String newValue = "" + entry.getValue();
String oldValue = "" + oldManifestMap.get(entry.getKey());
if (!newValue.equals(oldValue)) {
patch.getFilesToUpdate().add(entry.getKey());
}
oldManifestMap.remove(entry.getKey());
}
}
for (Map.Entry<String, String> entry : oldManifestMap.entrySet()) {
patch.getFilesToDelete().add(entry.getKey());
}
return patch;
}
/**
* Reads the bundle version from manifest.
* @param manifest
* @return
* @throws IOException
* @throws ManifestParseException
*/
public static long readBundleVersion(File manifest) throws IOException, ManifestParseException {
if (manifest == null || !manifest.exists()) {
return -1L;
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(manifest));
String line = reader.readLine();
if (line == null || !line.matches(BUNDLE_VERSION_HEAD_PATTERN)) {
throw new ManifestParseException();
}
return Long.parseLong(line.replaceAll(BUNDLE_VERSION_REGEXP, ""));
} finally {
closeInputStream(reader);
}
}
/**
* Reads the bundle version from manifest.
* @param manifest
* @return
* @throws IOException
* @throws ManifestParseException
*/
public static boolean isBundleRequireForceUpdate(File manifest) throws IOException, ManifestParseException {
if (manifest == null || !manifest.exists()) {
return false;
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(manifest));
reader.readLine();
String line = reader.readLine();
if (line == null || !line.startsWith(FORCE_UPDATE_SIGN_HEAD_PATTERN)) {
throw new ManifestParseException();
}
return "true".equalsIgnoreCase(line.replaceAll(FORCE_UPDATE_SIGN_HEAD_PATTERN, ""));
} finally {
closeInputStream(reader);
}
}
private static void closeInputStream(BufferedReader reader) {
if (reader == null) {
return;
}
try {
reader.close();
} catch (IOException e) {
}
}
private static Map<String, String> translate(File manifest) throws IOException {
if (manifest == null || !manifest.exists()) {
return Collections.<String, String> emptyMap();
}
Map<String, String> map = new HashMap<String, String>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(manifest));
String line;
String[] columns;
while ((line = reader.readLine()) != null) {
if (line.startsWith(COMMENT_SYM)) {
continue;
}
columns = line.split(COLUMN_SYM, -1);
if (columns.length >= 2) {
map.put(columns[0], columns[1]);
}
}
} finally {
closeInputStream(reader);
}
return map;
}
/**
* Gets specific bundle's manifest by the specific directory.
* @param directory
* @return
*/
public static File getBundleManifest(File directory) {
return new File(directory, MANIFEST_FILENAME);
}
}