Author: bleny Date: 2010-06-03 15:11:32 +0200 (Thu, 03 Jun 2010) New Revision: 58 Url: http://nuiton.org/repositories/revision/diswork/58 Log: licence plugin config ; some bugfixs Added: trunk/src/license/ trunk/src/license/project.xml Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/EntryUtil.java trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/PastryDisworkMap.java trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/Storage.java trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemPastryTest.java trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemTest.java trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/storage/EntryUtilTest.java Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java 2010-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/DisworkFileSystem.java 2010-06-03 13:11:32 UTC (rev 58) @@ -34,6 +34,12 @@ private static final Log log = LogFactory.getLog(DisworkFileSystem.class); + /** number of try to acquire a lock before giving up */ + protected static final int LOCK_MAX_NUMBER_OF_TRY = 10; + + /** time (ms) to wait between two try to acquire a lock */ + protected static final int LOCK_WAIT = 10 * 1000; // ten seconds + /** default constructor (uses default configuration parameters) * @throws IOException */ @@ -147,10 +153,42 @@ // store file before meta info storage.putFile(newFileId, source); - // update meta info directory - storage.putDirectory(parentId, newContent); + + // update directory content + int numberOfTry = 0; + boolean lockAcquired = false; + while (numberOfTry <= LOCK_MAX_NUMBER_OF_TRY && !lockAcquired) { + lockAcquired = storage.tryToLock(parentId); + if (lockAcquired) { + storage.putDirectory(parentId, newContent); + storage.unLock(parentId); + } else { + log.info(parent + " is locked and can't be written"); + try { + Thread.sleep(LOCK_WAIT); + } catch (InterruptedException e) { + log.info("exception catch", e); + throw new IOException + ("interrupted while trying to acquire lock", e); + } + } + } + + if (!lockAcquired) { + // fail, parent dir have not been written + throw new ConcurrentModificationException + ("can't write " + parent + " directory is locked"); + } + } else if (EntryUtil.isLink(entryParent)) { + String linkTarget = storage.getLink( + EntryUtil.getIdFromEntry(entryParent)); + String newTarget = EntryUtil.resolveLink(parent, linkTarget); + write(newTarget, fileName, source); + } else if (EntryUtil.isFile(entryParent)) { + throw new IOException(parent + " is not a directory"); } else { - throw new IOException(parent + " is not a directory"); + log.warn("strange entry" + entryParent); + throw new IOException("strange entry" + entryParent); } } @@ -187,12 +225,20 @@ // store file before meta info storage.putDirectory(newDirectoryId, - EntryUtil.newEmptyDirectoryContent()); + EntryUtil.EMPTY_DIRECTORY_CONTENT); // update meta info directory storage.putDirectory(parentId, newContent); + } else if (EntryUtil.isLink(entryParent)) { + String linkTarget = storage.getLink( + EntryUtil.getIdFromEntry(entryParent)); + String newTarget = EntryUtil.resolveLink(parent, linkTarget); + createDirectory(newTarget, dirName); + } else if (EntryUtil.isFile(entryParent)) { + throw new IOException(parent + " is not a directory"); } else { - throw new IOException(parent + " is not a directory"); + log.warn("strange entry" + entryParent); + throw new IOException("strange entry" + entryParent); } } @@ -217,13 +263,16 @@ protected void createSymbolicLink(String parent, String name, String target) throws IOException { - if (target.startsWith("/")) { + if (target.startsWith(EntryUtil.PATH_SEPARATOR)) { // target is absolute } else { // target is relative, taking this in consideration target = EntryUtil.resolveLink(parent, target); } + log.info("trying to create symbolic link named " + name + " at path " + + parent + " with target \"" + target + "\""); + if (exists(target)) { String entryParent = walk(parent); @@ -243,8 +292,16 @@ storage.putLink(newLinkId, target); // update meta info directory storage.putDirectory(parentId, newContent); + } else if (EntryUtil.isLink(entryParent)) { + String linkTarget = storage.getLink( + EntryUtil.getIdFromEntry(entryParent)); + String newTarget = EntryUtil.resolveLink(parent, linkTarget); + createSymbolicLink(newTarget, name, target); + } else if (EntryUtil.isFile(entryParent)) { + throw new IOException(parent + " is not a directory"); } else { - throw new IOException(parent + " is not a directory"); + log.warn("strange entry" + entryParent); + throw new IOException("strange entry" + entryParent); } @@ -271,6 +328,9 @@ * @see #delete(String) */ protected void delete(String parent, String name) throws IOException { + // FIXME 20100602 bleny this implementation leaks + // only the association path => id of the metablock is removed, all + // block remains String entryParent = walk(parent); if (entryParent == null) { @@ -284,8 +344,7 @@ String entry = EntryUtil.findEntryInDirectory(content, name); String idToRemove = EntryUtil.getIdFromEntry(entry); - String newContent = EntryUtil.removeEntryFromEntries( - content, name); + String newContent = EntryUtil.removeEntryFromEntries(content, name); // check if not removing a non-empty directory if (EntryUtil.isDirectory(entry)) { @@ -294,7 +353,7 @@ storage.getDirectory(innerDirectoryId); // checking the emptiness of the directory if (!innerDirectoryContent.equals( - EntryUtil.newEmptyDirectoryContent())) { + EntryUtil.EMPTY_DIRECTORY_CONTENT)) { // directory is not empty throw new IOException ("trying to remove a non-empty directory"); @@ -306,8 +365,16 @@ // store file before meta info storage.remove(idToRemove); + } else if (EntryUtil.isLink(entryParent)) { + String linkTarget = storage.getLink( + EntryUtil.getIdFromEntry(entryParent)); + String newTarget = EntryUtil.resolveLink(parent, linkTarget); + delete(newTarget, name); + } else if (EntryUtil.isFile(entryParent)) { + throw new IOException(parent + " is not a directory"); } else { - throw new IOException(parent + " is not a directory"); + log.warn("strange entry" + entryParent); + throw new IOException("strange entry" + entryParent); } } @@ -335,7 +402,7 @@ result = new ArrayList<String>(); String content = storage.getDirectory( EntryUtil.getIdFromEntry(entry)); - if (EntryUtil.newEmptyDirectoryContent().equals(content)) { + if (EntryUtil.EMPTY_DIRECTORY_CONTENT.equals(content)) { // directory is empty, add nothing } else { String[] entries = content.split( @@ -380,10 +447,10 @@ // FIXME 20105021 bleny works fine but is not understandable String result = null; - if (path.equals("/")) { + if (path.equals(EntryUtil.ROOT_DIRECTORY)) { return EntryUtil.TYPE.D + EntryUtil.ENTRY_SEPARATOR - + "/" + EntryUtil.ENTRY_SEPARATOR - + "/"; + + EntryUtil.ROOT_DIRECTORY + EntryUtil.ENTRY_SEPARATOR + + EntryUtil.ROOT_DIRECTORY; } String parentPath = EntryUtil.getParentFromPath(path); @@ -391,7 +458,7 @@ if (content == null) { // start of walk content = storage.getRootDirectory(); - result = walk(path, "/", content); + result = walk(path, EntryUtil.ROOT_DIRECTORY, content); } else if (parentPath.equals(current)) { // in the last directory // recuperation de l'element a traiter dans p @@ -414,7 +481,7 @@ String tail; // the path still remaining when in current - if (current.equals("/")) { + if (current.equals(EntryUtil.ROOT_DIRECTORY)) { tail = path.substring(current.length()); } else { tail = path.substring(current.length() + 1); @@ -422,14 +489,16 @@ log.debug("current = " + current); log.debug("tail = " + tail); - String[] elementsNames = tail.split("/"); + String[] elementsNames = tail.split(EntryUtil.PATH_SEPARATOR); String p = elementsNames[0]; log.info("in intermediate dir " + current + ", looking for " + p); // mise a jour de current - if (current.equals("/")) current = ""; // avoid "//path" next line - current += "/" + p; + if (current.equals(EntryUtil.ROOT_DIRECTORY)) { + current = ""; // avoid "//path" next line + } + current += EntryUtil.PATH_SEPARATOR + p; String entry = EntryUtil.findEntryInDirectory(content, p); if (entry == null) { @@ -463,6 +532,6 @@ @Override public void close() throws IOException { storage.close(); - } + } } Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/EntryUtil.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/EntryUtil.java 2010-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/EntryUtil.java 2010-06-03 13:11:32 UTC (rev 58) @@ -32,21 +32,25 @@ public class EntryUtil { static public enum TYPE { /** Directory */ D, - /** Link */ L, - /** File */ F + /** Link */ L, + /** File */ F }; - static final int TYPE_LENGTH = 1; + static final public int TYPE_LENGTH = 1; static final public String ENTRY_SEPARATOR = ":"; static final public String ENTRIES_SEPARATOR = "\n"; static final public String BLOCKIDS_SEPARATOR = ";"; + static final public String PATH_SEPARATOR = "/"; + static final public String ROOT_DIRECTORY = "/"; + static final public String EMPTY_DIRECTORY_CONTENT = ""; + static final public String LOCK_SEPARATOR = "%"; - static final int ENTRY_SEPARATOR_LENGTH = ENTRY_SEPARATOR.length(); + static final public int ENTRY_SEPARATOR_LENGTH = ENTRY_SEPARATOR.length(); /** * This charset is forced in string-to-bytes and bytes-to-string conversions */ - static protected Charset CHARSET = Charset.forName("UTF-8"); + static final protected Charset CHARSET = Charset.forName("UTF-8"); /** * This is a utility class thus should not be instantiated @@ -141,13 +145,6 @@ /** * - */ - static public String newEmptyDirectoryContent() { - return ""; - } - - /** - * * @param content the string content of the directory * (all entries before add) * @param type the type of the new entry @@ -164,10 +161,15 @@ static public int getTotalSizeFromMetaBlock(String metaBlock) { // dealing with empty meta-block (for empty directory or file) - if (metaBlock.equals("0")) return 0; - String result = metaBlock.substring(0, - metaBlock.indexOf(BLOCKIDS_SEPARATOR)); - return Integer.valueOf(result); + Integer result = null; + if (metaBlock.equals("0")) { + result = 0; + } else { + String resultAsString = metaBlock.substring(0, + metaBlock.indexOf(BLOCKIDS_SEPARATOR)); + result = Integer.valueOf(resultAsString); + } + return result; } static public String[] getBlockIdsFromMetaBlock(String metaBlock) { @@ -218,7 +220,7 @@ public static String getParentFromPath(String path) { String parent = FilenameUtils.getFullPathNoEndSeparator(path); if (parent.isEmpty()) { - parent = "/"; + parent = ROOT_DIRECTORY; } return parent; } @@ -227,4 +229,25 @@ return FilenameUtils.getName(path); } + public static String getOwnerFromLock(byte[] lock) { + String lockAsString = bytesToString(lock); + String lockInfo[] = lockAsString.split(LOCK_SEPARATOR); + String owner = lockInfo[0]; + return owner; + } + + public static Long getTimeFromLock(byte[] lock) { + String lockAsString = bytesToString(lock); + String lockInfo[] = lockAsString.split(LOCK_SEPARATOR); + Long lockAge = Long.parseLong(lockInfo[1]); + return lockAge; + } + + public static byte[] newLock(String ownerId) { + Long currentDate = System.currentTimeMillis(); + String lock = ownerId + LOCK_SEPARATOR + currentDate; + byte[] result = EntryUtil.stringToBytes(lock); + return result; + } + } Modified: trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/PastryDisworkMap.java =================================================================== --- trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/PastryDisworkMap.java 2010-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/PastryDisworkMap.java 2010-06-03 13:11:32 UTC (rev 58) @@ -1,6 +1,8 @@ package org.nuiton.disworkfs.storage; import java.io.IOException; +import java.net.BindException; +import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Arrays; @@ -120,15 +122,17 @@ while(factory == null && numberOfTry <= 10) { try { factory = new SocketPastryNodeFactory(nidFactory, bindport, env); - } catch (java.net.ConnectException e) { + } catch (BindException e) { + throw new IOException("unable to bind to port" + bindport); + } catch (ConnectException e) { + // this occurs some times, it may work after some time... numberOfTry += 1; + try { + Thread.sleep(10 * 1000); + } catch (InterruptedException ee) { + throw new IOException("Pastry boot process interrupted", ee); + } } - try { - Thread.sleep(10000); - } catch (InterruptedException e) { - log.info("exception catch", e); - e.printStackTrace(); - } } if (factory == null) { throw new IOException("unable to connect"); @@ -147,16 +151,14 @@ try { node.wait(500); } catch (InterruptedException e) { - // TODO 20100528 bleny Auto-generated catch block - log.info("exception catch", e); - e.printStackTrace(); + throw new IOException("Pastry boot process interrupted", e); } // abort if can't join if (node.joinFailed()) { throw new IOException("Could not join the FreePastry ring. Reason:"+node.joinFailedReason()); } - } + } } log.info("finished creating new node " + node); 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-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/main/java/org/nuiton/disworkfs/storage/Storage.java 2010-06-03 13:11:32 UTC (rev 58) @@ -9,6 +9,8 @@ import java.util.List; import java.util.Map; +import javax.swing.RowFilter.Entry; + import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -27,6 +29,18 @@ protected static final long LOCK_VALID_TIME = 60 * 60 * 1000; + protected String ownerId = EntryUtil.generateId(); + + protected static String keyToLockKey(String key) { + return key + "_lock"; + } + + protected static String keyToNewDataKey(String key) { + return key + "_new_data"; + } + + // FIXME 20100602 bleny this collection should be stored somewhere in + // the map so another node will perform remove if this one fail protected List<String> idsToBeRemoved = new ArrayList<String>(); /** @@ -44,8 +58,7 @@ protected ByteArrayInputStream currentBlock; - protected int available; - + protected int numberOfAvailableBytes; public SplitBlocksInputStream(Map<String, byte[]> map, String id) { super(); @@ -75,11 +88,11 @@ } int result = currentBlock.read(); - available -= 1; + numberOfAvailableBytes -= 1; if(log.isDebugEnabled()) { log.debug("reading block number " + blockIdsIndex + - " (available = " + available + ")" + + " (available = " + numberOfAvailableBytes + ")" + " returns " + result); } return result; @@ -93,9 +106,9 @@ String metaBlock = EntryUtil.bytesToString(bytes); blockIds = EntryUtil.getBlockIdsFromMetaBlock(metaBlock); blockIdsIndex = -1; - available = EntryUtil.getTotalSizeFromMetaBlock(metaBlock); + numberOfAvailableBytes = EntryUtil.getTotalSizeFromMetaBlock(metaBlock); log.debug("initializing stream with meta block \"" + metaBlock - + "\" (" + blockIds.length + " blocks, " + available + + "\" (" + blockIds.length + " blocks, " + numberOfAvailableBytes + " bytes)"); } } @@ -103,7 +116,7 @@ @Override public int available() { checkInitialization(); - return available; + return numberOfAvailableBytes; } } @@ -114,17 +127,21 @@ public Storage(DisworkFileSystemConfig disworkConfig) throws IOException { this.disworkConfig = disworkConfig; + + // instantiating a map according to config directives if (disworkConfig.useInMemoryMap()) { log.info("using in-memory map"); - this.map = new InMemoryDisworkMap(); - putDirectory("/", EntryUtil.newEmptyDirectoryContent()); + map = new InMemoryDisworkMap(); } else { log.info("using Pastry map"); - this.map = new PastryDisworkMap(disworkConfig); - if (! map.containsKey("/")) { - putDirectory("/", EntryUtil.newEmptyDirectoryContent()); - } + map = new PastryDisworkMap(disworkConfig); } + + // creating root directory, if needed + if (! map.containsKey(EntryUtil.ROOT_DIRECTORY)) { + putDirectory(EntryUtil.ROOT_DIRECTORY, + EntryUtil.EMPTY_DIRECTORY_CONTENT); + } } /** @@ -132,7 +149,7 @@ * @throws IOException */ public String getRootDirectory() throws IOException { - String result = getDirectory("/"); + String result = getDirectory(EntryUtil.ROOT_DIRECTORY); return result; } @@ -189,7 +206,9 @@ } /** - * a put in the map, this involves split considerations and concurrency + * a put in the map, this involves split considerations and concurrency. + * a lock is acquired (it might have been acquired before). + * Lock is released at the end * @param key * @param value * @throws IOException @@ -197,90 +216,67 @@ protected void put(String key, InputStream value) throws IOException, ConcurrentModificationException { + // TODO 20100602 bleny locks should be signed to prevent concurrency : + // due to latency, a lock claimed may be obtained even if someone tryed + // to obtain it before + boolean lockAcquired = tryToLock(key); - String lockKey = key + "_lock"; - String newDataKey = key + "_newData"; - - // trying to acquire lock - Long currentDate = System.currentTimeMillis(); - log.info("trying to acquire a lock on " + key); - byte[] lock = map.put(lockKey, - EntryUtil.stringToBytes(currentDate.toString())); - - if (lock != null) { - // file is locked, check date - Long currentLock = Long.parseLong(EntryUtil.bytesToString(lock)); - Long lockAge = currentDate - currentLock; - if (lockAge > LOCK_VALID_TIME) { - log.info("lock is out-dated (" + lockAge + " ms old)"); - // this lock is out-dated, let's erase all data - String obsoleteMetaBlock = - EntryUtil.bytesToString(map.get(newDataKey)); - if (obsoleteMetaBlock != null) { - String[] obsoleteBlocksIds = - EntryUtil.getBlockIdsFromMetaBlock(obsoleteMetaBlock); - log.info("removing " + obsoleteBlocksIds.length + " old blocks"); - for (String obsoleteBlockId : obsoleteBlocksIds) { - map.remove(obsoleteBlockId); - } - } - } else { - log.info(key + " is currently written, stopping operation"); - map.put(lockKey, lock); - throw new ConcurrentModificationException("can't write due to concurrency"); - } - } - - log.info("lock on " + key + " acquired"); - - // here, we know we can write or an exception - // would have been thrown earlier - String blocksIds = ""; - int readResult = 0; - int totalSize = 0; + if (lockAcquired) { + log.info("lock on " + key + " acquired"); - String metaBlock = totalSize + blocksIds; - map.put(newDataKey, EntryUtil.stringToBytes(metaBlock)); - - // creating a buffer of the size of a block - int bufferSize = disworkConfig.getBlockSize(); - byte[] buffer = new byte[bufferSize]; + // here, we know we can write or an exception + // would have been thrown earlier + String blocksIds = ""; + int readResult = 0; + int totalSize = 0; - while ((readResult = value.read(buffer)) != -1) { - totalSize += readResult; + String metaBlock = totalSize + blocksIds; + String newDataKey = keyToNewDataKey(key); + map.put(newDataKey, EntryUtil.stringToBytes(metaBlock)); + + // creating a buffer of the size of a block + int bufferSize = disworkConfig.getBlockSize(); + byte[] buffer = new byte[bufferSize]; - byte[] newBlock = buffer; + while ((readResult = value.read(buffer)) != -1) { + totalSize += readResult; - // if the buffer is not full, truncate the block - if (readResult < buffer.length) { - newBlock = new byte[readResult]; - System.arraycopy(buffer, 0, newBlock, 0, readResult); - } + byte[] newBlock = buffer; - String id = EntryUtil.generateId(); - blocksIds += EntryUtil.BLOCKIDS_SEPARATOR + id; + // if the buffer is not full, truncate the block + if (readResult < buffer.length) { + newBlock = new byte[readResult]; + System.arraycopy(buffer, 0, newBlock, 0, readResult); + } - log.debug("saving new block (size = " + newBlock.length + ")" + String id = EntryUtil.generateId(); + blocksIds += EntryUtil.BLOCKIDS_SEPARATOR + id; + + log.debug("saving new block (size = " + newBlock.length + ")" + " at key " + id); - // copy block in map - map.put(id, newBlock); + // copy block in map + map.put(id, newBlock); - metaBlock = totalSize + blocksIds; + metaBlock = totalSize + blocksIds; - log.debug("putting metablock " + metaBlock + " at key " + key); + log.debug("putting metablock " + metaBlock + " at key " + key); + + map.put(newDataKey, EntryUtil.stringToBytes(metaBlock)); + + // updating lock + updateLock(key); + } - map.put(newDataKey, EntryUtil.stringToBytes(metaBlock)); + eraseDependenciesOfMetablock(key); + map.put(key, map.get(newDataKey)); - // updating lock - currentDate = System.currentTimeMillis(); - map.put(lockKey, EntryUtil.stringToBytes(currentDate.toString())); + unLock(key); + + } else { + throw new ConcurrentModificationException("key " + key + " is locked"); } - map.put(key, map.get(newDataKey)); - - log.info("release lock " + lockKey); - map.remove(lockKey); } /** @@ -307,5 +303,79 @@ clean(); map.close(); } + + /** + * + * @param key + * @return true if lock acquired, false is lock is owned by another + */ + public boolean tryToLock(String key) { + // trying to acquire lock + log.info("trying to acquire a lock on " + key); + String lockKey = keyToLockKey(key); + byte[] lock = map.put(lockKey, EntryUtil.newLock(ownerId)); + + Boolean result = null; + // if there was no lock or if current lock is mine + if (lock == null || (EntryUtil.getOwnerFromLock(lock).equals(ownerId))) { + // file is not locked, we have took the lock + result = true; + } else { + // file is locked by other node, check date + if (isObsolete(lock)) { + log.info("lock is out-dated"); + // this lock is out-dated, let's erase all data + eraseNewData(key); + result = true; + } else { + log.info(key + " is currently written, stopping operation"); + map.put(lockKey, lock); + result = false; + } + } + return result; + } + + protected void updateLock(String key) { + String lockKey = keyToLockKey(key); + map.put(lockKey, EntryUtil.newLock(ownerId)); + } + + public void unLock(String key) { + String lockKey = keyToLockKey(key); + map.remove(lockKey); + } + + protected void eraseNewData(String key) { + String newDataKey = keyToNewDataKey(key); + eraseDependenciesOfMetablock(newDataKey); + } + + /** + * the value at this key has to be a metablock + * @param key + */ + public void eraseDependenciesOfMetablock(String key) { + byte[] value = map.get(key); + if (value != null) { + String obsoleteMetaBlock = EntryUtil.bytesToString(value); + if (obsoleteMetaBlock != null) { + String[] obsoleteBlocksIds = + EntryUtil.getBlockIdsFromMetaBlock(obsoleteMetaBlock); + log.info("removing " + obsoleteBlocksIds.length + " old blocks"); + for (String obsoleteBlockId : obsoleteBlocksIds) { + map.remove(obsoleteBlockId); + } + } + } + } + + protected boolean isObsolete(byte[] lock) { + Long currentDate = System.currentTimeMillis(); + Long currentLockTime = EntryUtil.getTimeFromLock(lock); + Long lockAge = currentDate - currentLockTime; + return lockAge > LOCK_VALID_TIME; + } + } \ No newline at end of file Modified: trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemPastryTest.java =================================================================== --- trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemPastryTest.java 2010-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemPastryTest.java 2010-06-03 13:11:32 UTC (rev 58) @@ -17,15 +17,12 @@ public class DisworkFileSystemPastryTest extends DisworkFileSystemTest { + protected Integer bootstrapPort; + /** * this code executed after {@link DisworkFileSystemTest#setUp()} * @throws Exception */ - - private static final Log log = LogFactory.getLog(DisworkFileSystemPastryTest.class); - - protected Integer bootstrapPort; - @Before public void setUpFileSystem() throws Exception { // finally, initiate the fileSystem Modified: trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemTest.java =================================================================== --- trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemTest.java 2010-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/DisworkFileSystemTest.java 2010-06-03 13:11:32 UTC (rev 58) @@ -324,4 +324,23 @@ fail(); } } + + @Test + public void testLinks() throws Exception { + fileSystem.createDirectory("/dir"); + fileSystem.createDirectory("/dir/subdir"); + fileSystem.createDirectory("/otherdir"); + + fileSystem.createSymbolicLink("/link", "dir/subdir"); + fileSystem.createSymbolicLink("/link/subsubdirlink", "/otherdir"); + List<String> readResult = fileSystem.readDirectory("/dir/subdir"); + assertEquals(1, readResult.size()); + assertTrue(readResult.contains("subsubdirlink")); + + fileSystem.createDirectory("/link/subsubdirlink/finaldir"); + readResult = fileSystem.readDirectory("/otherdir"); + assertEquals(1, readResult.size()); + assertTrue(readResult.contains("finaldir")); + + } } Modified: trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/storage/EntryUtilTest.java =================================================================== --- trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/storage/EntryUtilTest.java 2010-06-03 10:23:17 UTC (rev 57) +++ trunk/diswork-fs/src/test/java/org/nuiton/disworkfs/storage/EntryUtilTest.java 2010-06-03 13:11:32 UTC (rev 58) @@ -130,6 +130,15 @@ } @Test + public void testGetParentFromPath() { + String path; + path = "/file"; + assertEquals("/", EntryUtil.getParentFromPath(path)); + path = "/dir/file"; + assertEquals("/dir", EntryUtil.getParentFromPath(path)); + } + + @Test public void testGetTotalSizeFromMetaBlock() { assertEquals(12345, EntryUtil.getTotalSizeFromMetaBlock(metaBlock)); } Added: trunk/src/license/project.xml =================================================================== --- trunk/src/license/project.xml (rev 0) +++ trunk/src/license/project.xml 2010-06-03 13:11:32 UTC (rev 58) @@ -0,0 +1,20 @@ +<?xml version='1.0' encoding='UTF-8'?> +<project xmlns="http://maven-site.nuiton.org/maven-license-plugin/1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven-site.nuiton.org/maven-license-plugin/1.0.0 http://maven-site.nuiton.org/maven-license-plugin/licenseProjectDescriptor-1.0.0.xsd"> + <mainLicense>lgpl_v3</mainLicense> + <headers> + <header> + <licenseName>lgpl_v3</licenseName> + <commentStyle>java</commentStyle> + <fileSets> + <fileSet> + <basedir>all/src</basedir> + <includes> + <include>**/*.java</include> + </includes> + </fileSet> + </fileSets> + </header> + </headers> +</project>