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 org.wyona.yarep.impl.VFileSystemMapImpl.ChildrenFilter; 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; /** * */ public class DefaultMapImpl implements Map { private static Logger log = LogManager.getLogger(DefaultMapImpl.class); protected File pathsDir; protected Pattern[] ignorePatterns; protected ChildrenFilter childrenFilter = new ChildrenFilter(); private static String YAREP_UID_SUFFIX = "yarep-uid"; /** * */ public void readConfig(Configuration mapConfig, File repoConfigFile) throws RepositoryException { try { pathsDir = new File(mapConfig.getAttribute("src")); if (!pathsDir.isAbsolute()) { pathsDir = FileUtil.file(repoConfigFile.getParent(), pathsDir.toString()); } log.debug(pathsDir.toString()); // TODO: Throw Exception if (!pathsDir.exists()) log.error("No such file or directory: " + pathsDir); Configuration[] ignoreElements = mapConfig.getChildren("ignore"); ignorePatterns = new Pattern[ignoreElements.length + 1]; // always ignore uid files: ignorePatterns[0] = Pattern.compile(".*\\." + YAREP_UID_SUFFIX); for (int i=0; i<ignoreElements.length; i++) { String patternString = ignoreElements[i].getAttribute("pattern"); ignorePatterns[i+1] = Pattern.compile(patternString); log.debug("adding ignore pattern: " + ignorePatterns[i+1].pattern()); } } catch(Exception e) { log.error(e); throw new RepositoryException("Could not read map configuration: " + repoConfigFile.getAbsolutePath() + e.getMessage(), e); } } protected boolean ignorePath(String path) { 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; } /** * Check if path is representing a resource */ public boolean isResource(Path path) throws RepositoryException { File file = new File(pathsDir + path.toString()); File uidFile = new File(pathsDir + path.toString() + File.separator + "." + YAREP_UID_SUFFIX); if(log.isDebugEnabled()) log.debug("UID File: " + uidFile); return (uidFile.isFile() || file.isFile()) && !isCollection(path); } /** * */ public boolean exists(Path path) throws RepositoryException { File file = new File(pathsDir + path.toString()); // TODO: Get name of repository for debugging ... //log.debug("Path (" + getName() + "): " + file); return file.exists() && !ignorePath(file.getPath()); } /** * */ public boolean delete(Path path) throws RepositoryException { /* File uidFile = new File(pathsDir + path.toString() + File.separator + "." + YAREP_UID_SUFFIX); if (uidFile.isFile()) uidFile.delete(); */ File file = new File(pathsDir + path.toString()); log.debug("delete from map: " + file); return org.wyona.commons.io.FileUtil.deleteDirectory(file); } /** * Check if path is representing a collection */ public boolean isCollection(Path path) throws RepositoryException { File file = new File(pathsDir + path.toString()); if(log.isDebugEnabled()) log.debug("Check if path is representing a collection: " + file); if (file.isDirectory()) { File uidFile = new File(pathsDir + path.toString() + File.separator + "." + YAREP_UID_SUFFIX); if (uidFile.isFile()) { try { BufferedReader br = new BufferedReader(new FileReader(uidFile)); String existingUID = br.readLine(); String type = br.readLine(); br.close(); if (log.isDebugEnabled()) log.debug("type: " + type); if (type != null && type.equals("collection")) { return true; } } catch (Exception e) { log.error(e.getMessage(), e); throw new RepositoryException("Error reading uid of path: " + path.toString() + ": " + e.getMessage(), e); } return false; } else { return true; } } return false; } /** * */ public Path[] getChildren(Path path) throws RepositoryException { File file = new File(pathsDir + path.toString()); String[] filenames = file.list(this.childrenFilter); // NOTE: This situation should only occur if isResource(Path) didn't work properly! 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("/")) { 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 { File uidFile = new File(pathsDir + path.toString() + File.separator + "." + YAREP_UID_SUFFIX); if (log.isDebugEnabled()) log.debug(pathsDir.toString() + ", " + uidFile.toString()); if (uidFile.exists()) { try { FileReader fr = new FileReader(uidFile); BufferedReader br = new BufferedReader(fr); String existingUID = br.readLine(); br.close(); fr.close(); return new UID(existingUID); } catch (Exception e) { log.error(e); throw new RepositoryException("Error reading uid of path: " + path.toString() + ": " + e.getMessage(), e); } } else { if(log.isDebugEnabled()) log.debug("uid file [" + uidFile + "] does not exist for path: " + path); } return null; } /** * Get UID */ public synchronized UID create(Path path, int type) throws RepositoryException { log.debug(pathsDir.toString()); File uidFile = new File(pathsDir + path.toString() + File.separator + "." + YAREP_UID_SUFFIX); log.debug(uidFile.toString()); // TODO: Shouldn't the uid be written only if the writer is being closed successfully! //String uid = "" + System.currentTimeMillis(); String uuid = org.apache.commons.id.uuid.UUID.randomUUID().toString(); //String uid = java.util.UUID.randomUUID().toString(); // Java 1.5.x try { File parent = new File(uidFile.getParent()); if (!parent.exists()) { log.warn("Directory will be created: " + parent); parent.mkdirs(); } // TODO: ... if (parent.isFile()) { log.warn("Parent is a file and not a directory: " + parent); } if (type == org.wyona.yarep.core.NodeType.RESOURCE) { FileWriter fw = new FileWriter(uidFile); fw.write(uuid); fw.close(); } else if (type == org.wyona.yarep.core.NodeType.COLLECTION) { // TODO: Should a uidFile also be written in the case of a collection?! FileWriter fw = new FileWriter(uidFile); fw.write(uuid); fw.close(); } else { log.error("Node type is neither resource nor collection!"); throw new RepositoryException("Node type is neither resource nor collection!"); } } catch (Exception e) { log.error(e.getMessage(), e); throw new RepositoryException("Error creating uid for path: " + path.toString() + ": " + e.getMessage(), e); } return new UID(uuid); } /** * */ public void addSymbolicLink(Path link, UID uid) throws RepositoryException { File uidFile = new File(pathsDir + link.toString() + File.separator + "." + YAREP_UID_SUFFIX); String uuid = uid.toString(); try { File parent = new File(uidFile.getParent()); if (!parent.exists()) { log.warn("Directory will be created: " + parent); parent.mkdirs(); } // TODO: ... if (parent.isFile()) { log.warn("Parent is a file and not a directory: " + parent); } FileWriter fw = new FileWriter(uidFile); fw.write(uuid); fw.close(); } catch (Exception e) { log.error(e); throw new RepositoryException("Error creating uid for path: " + link.toString() + ": " + e.getMessage(), e); } } protected class ChildrenFilter implements FilenameFilter { public boolean accept(File dir, String name) { if (DefaultMapImpl.this.ignorePath(name)) { return false; } else { return true; } } } }