package org.wyona.yarep.impl;
import org.apache.avalon.framework.configuration.Configuration;
import org.wyona.commons.io.FileUtil;
import org.wyona.yarep.core.Map;
import org.wyona.yarep.core.Path;
import org.wyona.yarep.core.RepositoryException;
import org.wyona.yarep.core.UID;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.FilenameFilter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
/**
* Virtual file system map which is basically a one to one map
*/
public class VFileSystemMapImpl implements Map {
private static Logger log = LogManager.getLogger(VFileSystemMapImpl.class);
protected File pathsDir;
protected Pattern[] ignorePatterns;
protected ChildrenFilter childrenFilter = new ChildrenFilter();
/**
*
*/
public void readConfig(Configuration mapConfig, File repoConfigFile) throws RepositoryException {
try {
setPathsDir(new File(mapConfig.getAttribute("src")), repoConfigFile);
if (mapConfig != null) {
Configuration[] ignoreElements = mapConfig.getChildren("ignore");
setIgnorePatterns(ignoreElements);
}
} catch(Exception e) {
log.error(e);
throw new RepositoryException("Could not read map configuration: "
+ repoConfigFile.getAbsolutePath() + e.getMessage(), e);
}
}
/**
* Set paths directory
*/
public void setPathsDir(File src, File repoConfigFile) throws RepositoryException {
pathsDir = src;
if (!pathsDir.isAbsolute()) {
pathsDir = FileUtil.file(repoConfigFile.getParent(), pathsDir.toString());
}
log.info("Paths dir: " + pathsDir.toString());
if (!pathsDir.exists()) {
log.warn("No such file or directory '" + pathsDir + "', hence we will create it...");
pathsDir.mkdirs();
//throw new RepositoryException("No such file or directory: " + pathsDir);
}
}
/**
* Test if path should be ignored
*/
protected boolean ignorePath(String path) {
if (ignorePatterns != null) {
for (int i=0; i<this.ignorePatterns.length; i++) {
Matcher matcher = this.ignorePatterns[i].matcher(path);
if (matcher.matches()) {
if (log.isDebugEnabled()) {
log.debug(path + " matched ignore pattern " + ignorePatterns[i].pattern());
}
return true;
}
}
}
if (log.isDebugEnabled()) {
log.debug(path + " did not match any ignore patterns");
}
return false;
}
/**
*
*/
public boolean isResource(Path path) throws RepositoryException {
File file = new File(pathsDir + path.toString());
return file.isFile();
}
/**
* @see org.wyona.yarep.core.Map#exists(Path)
*/
public boolean exists(Path path) throws RepositoryException {
File file = new File(pathsDir + path.toString());
// TODO: Get name of repository for debugging ...
//log.debug("File: " + file);
return file.exists() && !ignorePath(file.getPath());
}
/**
*
*/
public boolean delete(Path path) throws RepositoryException {
// don't do anything because if we delete the file here, the delete
// in the storage will fail later
//File file = new File(pathsDir + path.toString());
//return file.delete();
return true;
}
/**
*
*/
public boolean isCollection(Path path) throws RepositoryException {
File file = new File(pathsDir + path.toString());
return file.isDirectory();
}
/**
* Get children
*/
public Path[] getChildren(Path path) throws RepositoryException {
File file = new File(pathsDir + path.toString());
if (!file.exists()) {
log.warn("No such file or directory: " + file);
return new Path[0];
}
String[] filenames = file.list(this.childrenFilter);
// NOTE: This situation should only occur if one is trying to get children for a file than a directory! One might want to consider to test first with isResource() or isCollection().
if (filenames == null) {
log.warn("No children: " + path + " (" + file + ")");
return new Path[0];
}
log.debug("Number of children: " + filenames.length + " (" + file + ")");
Path[] children = new Path[filenames.length];
for (int i = 0;i < children.length; i++) {
if (path.toString().endsWith(File.separator)) {
children[i] = new Path(path + filenames[i]);
} else {
// NOTE: Do not use File.separator here, because it's the repository path and not the Operating System File System path
children[i] = new Path(path + "/" + filenames[i]);
}
log.debug("Child: " + children[i]);
}
return children;
}
/**
* Get UID
*/
public synchronized UID getUID(Path path) throws RepositoryException {
// TODO: Check if leading slash should be removed ...
return new UID(path.toString());
}
/**
* Create UID and corresponding map entries
*/
public synchronized UID create(Path path, int type) throws RepositoryException {
// TODO: Check if leading slash should be removed ...
File parent = new File(pathsDir + File.separator + path.getParent().toString());
if (!parent.exists()) {
log.info("Parent directories will be created: " + parent);
parent.mkdirs();
}
if (type == org.wyona.yarep.core.NodeType.COLLECTION) {
File dir = new File(parent, path.getName());
boolean created = dir.mkdir();
if (created) {
log.info("Collection has been created: " + dir.getAbsolutePath());
} else {
log.warn("Collection has NOT been created: " + dir.getAbsolutePath());
}
} else {
try {
File file = new File(parent, path.getName());
boolean created = file.createNewFile();
if(!created) {
log.warn("File has NOT been created: " + file);
} else {
log.info("Resource has been created: " + file.getAbsolutePath());
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
return new UID(path.toString());
}
/**
*
*/
public void addSymbolicLink(Path path, UID uid) throws RepositoryException {
throw new RepositoryException("Symbolic links not implemented for virtual file system!");
}
/**
* Ignore all children which are matched by an ignore pattern (see repository configuration, e.g. src/test/repository/node-fs-example/repository.xml)
*/
protected class ChildrenFilter implements FilenameFilter {
public ChildrenFilter() {
}
public boolean accept(File dir, String name) {
if (VFileSystemMapImpl.this.ignorePath(name)) {
return false;
} else {
return true;
}
}
}
/**
* Set ignore patterns
*/
public void setIgnorePatterns(Configuration[] ignoreElements) throws org.apache.avalon.framework.configuration.ConfigurationException {
if (ignoreElements != null) {
ignorePatterns = new Pattern[ignoreElements.length];
for (int i=0; i<ignoreElements.length; i++) {
String patternString = ignoreElements[i].getAttribute("pattern");
ignorePatterns[i] = Pattern.compile(patternString);
log.debug("adding ignore pattern: " + ignorePatterns[i].pattern());
}
} else {
ignorePatterns = null; // see ignorePath(String)
}
}
}