Author: bpoussin Date: 2010-05-18 21:34:53 +0200 (Tue, 18 May 2010) New Revision: 43 Url: http://nuiton.org/repositories/revision/diswork/43 Log: Gros changement, rendre le code compilable est laisse en exercice a Bredan :D Added: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/EntryUtil.java trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/EntryUtilTest.java Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DistributedFileSystem.java trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/Storage.java Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DistributedFileSystem.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DistributedFileSystem.java 2010-05-18 19:34:40 UTC (rev 42) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DistributedFileSystem.java 2010-05-18 19:34:53 UTC (rev 43) @@ -4,7 +4,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.URISyntaxException; public interface DistributedFileSystem extends Closeable { @@ -15,7 +14,8 @@ * a path to a file on the virtual FS * @return true if the file exists, false if not */ - public boolean exists(String path); + public boolean exists(String path) throws IOException; +; /** * write a file @@ -27,7 +27,7 @@ * @throws IOException * if problems occurs while reading the source or writing on VFS */ - public void write(String path, InputStream source) throws IOException; + public void write(String parent, String file, InputStream source) throws IOException; /** * read a file on the VFS, the file is downloaded if needed (may take some Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java 2010-05-18 19:34:40 UTC (rev 42) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java 2010-05-18 19:34:53 UTC (rev 43) @@ -1,10 +1,14 @@ package org.nuiton.disworkfs; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.UUID; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.disworkfs.nodes.DirectoryNode; @@ -14,6 +18,8 @@ import org.nuiton.disworkfs.operations.Write; import org.nuiton.disworkfs.storage.Storage; import org.nuiton.disworkfs.storage.StorageStub; +import org.nuiton.util.FileUtil; +import sun.management.snmp.jvminstr.JvmThreadInstanceEntryImpl.ThreadStateMap.Byte0; public class DisworkFileSystem implements DistributedFileSystem { @@ -30,104 +36,118 @@ } @Override - public boolean exists(String path) { - boolean exists = storage.containsKey(path); - log.info("exists(" + path + ") returns " + exists); - return exists; + public boolean exists(String path) throws IOException { + String entry = walk(path, null, null); + boolean result = entry != null; + return result; } - @Override - public InputStream read(String path) throws FileNotFoundException, - IOException { + /** + * Return id of the last element in path. + * + * @param path + * @return null if path is not valid + */ + protected String walk(String path, String current, String content) throws IOException { + String result = null; + if (content == null) { + // start of walk + content = storage.getRoot(); + result = walk(path, "/", content); + } else if (FilenameUtils.getFullPathNoEndSeparator(path).equals(current)) { + // in the last directory - log.info("trying read(" + path + ")"); - - if (exists(path)) { - Node target = storage.get(path); - Read read = new Read(storage); - try { - target.operation(read); - return read.getInputStream(); - } catch (Exception eee) { - throw new IOException("diswork intern error", eee); + // recuperation du directory a traiter dans p + String tail = path.substring(current.length()); + String[] dirNames = tail.split(EntryUtil.ENTRY_SEPARATOR); + String p = dirNames[0]; + + String entry = EntryUtil.find(content, p); + if (entry != null) { + result = entry; + } else { + result = null; } } else { - log.warn("file not found : " + path); - throw new FileNotFoundException(); - } - } - - public void create(String path) throws IOException { - - // First check everything is OK with parent dir - log.info("trying create(" + path + ")"); - - if (exists(path)) { - - throw new IOException("can't create " + path + ", already exists"); - - } else { - - String parentPath = FilenameUtils.getFullPathNoEndSeparator(path); - - // needed if parent dir is root - if (parentPath.equals("")) { - parentPath = "/"; - } - - Node parentNode = storage.get(parentPath); - - if (parentNode == null) { - throw new IOException("can't create file " + path - + ", " + parentPath + " doesn't exists"); - } - - if (parentNode.isDirectory()) { - - DirectoryNode parent = (DirectoryNode) parentNode; - - String fileName = FilenameUtils.getName(path); + // in middle of path - log.info("adding \"" + fileName + "\" to " + parentPath + " (" + parent + ")"); - - parent.add(fileName); - - storage.put(path, new FileNode(null)); - + // recuperation du directory a traiter dans p + String tail = path.substring(current.length()); + String[] dirNames = tail.split(EntryUtil.ENTRY_SEPARATOR); + String p = dirNames[0]; + + // mise a jour de current + current += "/" + p; + + String entry = EntryUtil.find(content, p); + if (entry != null) { + if (EntryUtil.isDirectory(entry)) { + String id = EntryUtil.getId(entry); + content = storage.getDirectory(id); + result = walk(path, current, content); + } else if (EntryUtil.isLink(entry)) { + String id = EntryUtil.getId(entry); + String linkContent = storage.getLink(id); + String newTarget = EntryUtil.getAbsolutePath(current, linkContent); + newTarget += path.substring(current.length()); + + // restart walk from / + result = walk(newTarget, null, null); + } else { + // erreur, find file in path like '/dir1/dir2/filename/dir3' + result = null; + } } else { - throw new IOException("can't write : " + parentPath + "is not a directory"); + result = null; } } - + return result; } @Override - public void write(String path, InputStream source) throws IOException { - write(path, source, true); - } - - public void write(String path, InputStream source, boolean forceCreate) - throws IOException { + public InputStream read(String path) throws FileNotFoundException, + IOException { - if (! exists(path)) { - if (forceCreate) { - create(path); - } else { - throw new IOException("can't write not created file"); - } + String entry = walk(path, null, null); + if (entry == null) { + throw new FileNotFoundException(path); } - try { - Write write = new Write(storage, source); - - Node target = storage.get(path); - target.operation(write); - } catch (Exception eee) { - throw new IOException("diswork intern error", eee); + InputStream result; + if (EntryUtil.isLink(entry)) { + String id = EntryUtil.getId(entry); + String link = storage.getLink(id); + String newTarget = EntryUtil.getAbsolutePath(path, link); + result = read(newTarget); + } else if(EntryUtil.isDirectory(entry)) { + throw new IOException("target is not a file: " + path); + } else { + String id = EntryUtil.getId(entry); + result = storage.getFile(id); } + return result; } @Override + public void write(String parent, String file, InputStream source) throws IOException { + String entryParent = walk(parent, null, null); + if (EntryUtil.isDirectory(entryParent)) { + String idParent = EntryUtil.getId(entryParent); + String content = storage.getDirectory(idParent); + String id = EntryUtil.generateId(); + String newContent = EntryUtil.add(content, EntryUtil.TYPE.D, file, id); + + // store file before meta info + storage.put(id, source); + // update meta info directory + InputStream parentContent = new ByteArrayInputStream(newContent.getBytes()); + storage.put(idParent, parentContent); + } else { + throw new IOException(parent + " is not a directory"); + } + } + + @Override public void close() throws IOException { storage.close(); } Added: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/EntryUtil.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/EntryUtil.java (rev 0) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/EntryUtil.java 2010-05-18 19:34:53 UTC (rev 43) @@ -0,0 +1,108 @@ +/* *##% + * Copyright (c) 2010 poussin. All rights reserved. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + *##%*/ + +package org.nuiton.disworkfs; + + +import java.util.UUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class EntryUtil { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(EntryUtil.class); + + static final public String ENTRY_SEPARATOR = ":"; + + static final int TYPE_LENGTH = 1; + static final int UUID_LENGTH = UUID.randomUUID().toString().length(); + static final int ENTRY_SEPARATOR_LENGTH = ENTRY_SEPARATOR.length(); + + static public enum TYPE{D /*Directory*/, L /*Link*/, F /*File*/}; + + static public String add(String content, TYPE type, String name, String id) { + content += type.name() + ENTRY_SEPARATOR + name + ENTRY_SEPARATOR + id; + return content; + } + + static public String generateId() { + String result = UUID.randomUUID().toString(); + return result; + } + + static public boolean isDirectory(String entry) { + boolean result = entry.startsWith(TYPE.D.name()); + return result; + } + + static public boolean isLink(String entry) { + boolean result = entry.startsWith(TYPE.L.name()); + return result; + } + + /** + * find file name in directory content description + * + * @param directoryContent + * @param name + * @return null if name is not found + */ + static public String find(String directoryContent, String name) { + int index = directoryContent.indexOf(ENTRY_SEPARATOR + name + ENTRY_SEPARATOR); + + String result = null; + if (index != -1) { + result = directoryContent.substring( + index - TYPE_LENGTH, index + ENTRY_SEPARATOR_LENGTH + name.length()); + } + return result; + } + + static public String getId(String entry) { + int index = entry.lastIndexOf(ENTRY_SEPARATOR); + String result = entry.substring(index); + return result; + } + + static public String getName(String entry) { + int start = entry.indexOf(ENTRY_SEPARATOR); + int last = entry.lastIndexOf(ENTRY_SEPARATOR); + String result = entry.substring(start, last); + return result; + } + + static public TYPE getType(String entry) { + int index = entry.lastIndexOf(ENTRY_SEPARATOR); + String type = entry.substring(0, index); + TYPE result = TYPE.valueOf(type); + return result; + } + + static public String getAbsolutePath(String parent, String link) { + + } + +} Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/Storage.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/Storage.java 2010-05-18 19:34:40 UTC (rev 42) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/Storage.java 2010-05-18 19:34:53 UTC (rev 43) @@ -1,8 +1,15 @@ package org.nuiton.disworkfs.storage; +import java.io.ByteArrayInputStream; import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; import java.util.Map; +import java.util.Set; +import java.util.UUID; +import org.apache.commons.io.IOUtils; import org.nuiton.disworkfs.nodes.Node; /** @@ -53,6 +60,90 @@ * Since this storage may use ressources (sockets or stream on files), it * has to be closeable. */ -public interface Storage extends Map<String, Node>, Closeable { +public class Storage { + protected Map<String, byte[]> map; + + public Storage(Map<String, byte[]> map) { + this.map = map; + } + + public boolean exists(Object key) { + return map.containsKey(key); + } + + public String getRoot() throws IOException { + String result = getDirectory("/"); + return result; + } + + public String getDirectory(String uuid) throws IOException { + InputStream in = get(uuid); + // lecture de l'entry pour / + byte[] entryAsByte = new byte[in.available()]; + in.read(entry); + String entry = EntryUtil.byteToSting(entryAsByte); + byte[] contentAsByte = storage.get(entry); + if (EntryUtil.isDirectory(entry)) { + String content = EntryUtil.byteToSting(contentAsByte); + return content; + } else { + throw IOException("Root is not a directory"); + } + } + + /** + * return path to target file + * + * @param uuid + * @return + * @throws IOException + */ + public String getLink(String uuid) throws IOException { + InputStream in = get(uuid); + // lecture de l'entry pour / + byte[] entryAsByte = new byte[in.available()]; + in.read(entry); + String entry = EntryUtil.byteToSting(entryAsByte); + return entry; + } + + public InputStream getFile(String uuid) { + InputStream result = get(uuid); + return result; + } + + protected InputStream get(String uuid) { + byte[] uuidAsByte = map.get(key); + String uuid = EntryUtil.byteToSting(uuidAsByte); + byte[] content = map.get(uuid); + // TODO poussin 20100518 create specifique InputStream + // Lorsque le content pourra etre en plusieurs bon, il faudra + // ecrire un InputStream qui permet le chargement au fur et a mesure + // de la demande new InputStream(map, uuid) + ByteArrayInputStream result = new ByteArrayInputStream(content); + return result; + } + + public Object put(String key, InputStream value) { + // TODO poussin 20100518 split value in multiple block (see also get) + // il faudra decouper en plusieurs block plutot que de tout lire + // dans ce cas, il faut aussi stocker la liste des UUID genere pour + // chaque bloque + byte[] content = new byte[value.available()]; + value.read(content); + map.put(key, content); + } + + public Object remove(Object key) { + // TODO poussin 20100518 mark bloque to remove + map.remove(key); + } + + + + public void close() throws IOException { + throw new UnsupportedOperationException("Not supported yet."); + } + } Added: trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/EntryUtilTest.java =================================================================== --- trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/EntryUtilTest.java (rev 0) +++ trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/EntryUtilTest.java 2010-05-18 19:34:53 UTC (rev 43) @@ -0,0 +1,124 @@ +/* *##% + * Copyright (c) 2010 poussin. All rights reserved. + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + *##%*/ + +package org.nuiton.disworkfs; + + +import java.util.UUID; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Test; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class EntryUtilTest { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(EntryUtilTest.class); + + @Test + public void testIsDirectory() { + String d = EntryUtil.TYPE.D + EntryUtil.ENTRY_SEPARATOR + + "toto" + EntryUtil.ENTRY_SEPARATOR + + UUID.randomUUID().toString(); + + assertTrue(EntryUtil.isDirectory(d)); + + String f = EntryUtil.TYPE.F + EntryUtil.ENTRY_SEPARATOR + + "toto" + EntryUtil.ENTRY_SEPARATOR + + UUID.randomUUID().toString(); + + assertFalse(EntryUtil.isDirectory(f)); + + } + + @Test + public void testFind() { + String d1 = EntryUtil.TYPE.D + EntryUtil.ENTRY_SEPARATOR + + "toto" + EntryUtil.ENTRY_SEPARATOR + + UUID.randomUUID().toString(); + + String d2 = EntryUtil.TYPE.D + EntryUtil.ENTRY_SEPARATOR + + "titi" + EntryUtil.ENTRY_SEPARATOR + + UUID.randomUUID().toString(); + + String f = EntryUtil.TYPE.F + EntryUtil.ENTRY_SEPARATOR + + "tata" + EntryUtil.ENTRY_SEPARATOR + + UUID.randomUUID().toString(); + + String content = d1 + "\n" + d2 + "\n" + f; + + { + // recherche et trouve le nom + String entry = EntryUtil.find(content, "titi"); + assertEquals(entry, d2); + } + { + // recherche et ne trouve pas le nom + String entry = EntryUtil.find(content, "pastrouve"); + assertEquals(entry, null); + } + } + + @Test + public void testGetId() { + String id = UUID.randomUUID().toString(); + String d = EntryUtil.TYPE.D + EntryUtil.ENTRY_SEPARATOR + + "toto" + EntryUtil.ENTRY_SEPARATOR + + id; + + String id2 = EntryUtil.getId(d); + assertEquals(id, id2); + + } + + @Test + public void testGetName() { + String id = UUID.randomUUID().toString(); + String name = "truc"; + String d = EntryUtil.TYPE.D + EntryUtil.ENTRY_SEPARATOR + + name + EntryUtil.ENTRY_SEPARATOR + + id; + + String name2 = EntryUtil.getName(d); + assertEquals(name, name2); + + } + + @Test + public void testGetType() { + EntryUtil.TYPE type = EntryUtil.TYPE.D; + String id = UUID.randomUUID().toString(); + + String d = type + EntryUtil.ENTRY_SEPARATOR + + "toto" + EntryUtil.ENTRY_SEPARATOR + + id; + + EntryUtil.TYPE type2 = EntryUtil.getType(d); + assertEquals(type, type2); + + } +}