summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsnowleo <schneeleo@gmail.com>2012-11-03 00:24:54 +0100
committersnowleo <schneeleo@gmail.com>2012-11-03 00:24:54 +0100
commitc60beda40f3cd1a971cb76178bd6a73ccb814baa (patch)
tree55cccc550508b9fafd51197f9363ce5799eec547
parent3ce525f032db4d4ea356dceb6d1198e5734dfd73 (diff)
downloadEssentials-c60beda40f3cd1a971cb76178bd6a73ccb814baa.tar
Essentials-c60beda40f3cd1a971cb76178bd6a73ccb814baa.tar.gz
Essentials-c60beda40f3cd1a971cb76178bd6a73ccb814baa.tar.lz
Essentials-c60beda40f3cd1a971cb76178bd6a73ccb814baa.tar.xz
Essentials-c60beda40f3cd1a971cb76178bd6a73ccb814baa.zip
Add support for zipped User / Warp files
-rw-r--r--.gitignore3
-rw-r--r--Essentials/pom.xml45
-rw-r--r--Essentials/src/net/ess3/storage/StorageObjectMap.java135
-rw-r--r--Essentials/test/net/ess3/EssentialsTest.java14
4 files changed, 175 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore
index 164936d32..ed9bf34b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,4 +31,5 @@ manifest.mf
*.iws
.idea/
-EssentialsRelease/ \ No newline at end of file
+EssentialsRelease/
+/Essentials/dependency-reduced-pom.xml \ No newline at end of file
diff --git a/Essentials/pom.xml b/Essentials/pom.xml
index f3fd665ff..75b7823be 100644
--- a/Essentials/pom.xml
+++ b/Essentials/pom.xml
@@ -21,7 +21,17 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
- <version>0.11.4</version>
+ <version>0.11.6</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.4.1</version>
</dependency>
<!-- Test Depends -->
<dependency>
@@ -63,4 +73,37 @@
<version>1.2</version>
</dependency>
</dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>2.0</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <artifactSet>
+ <includes>
+ <include>commons-io:*</include>
+ <include>org.apache.commons:*</include>
+ </includes>
+ </artifactSet>
+ <minimizeJar>true</minimizeJar>
+ <relocations>
+ <relocation>
+ <pattern>org.apache.commons</pattern>
+ <shadedPattern>net.ess3.commons</shadedPattern>
+ </relocation>
+ </relocations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/Essentials/src/net/ess3/storage/StorageObjectMap.java b/Essentials/src/net/ess3/storage/StorageObjectMap.java
index bec082e31..945beb06a 100644
--- a/Essentials/src/net/ess3/storage/StorageObjectMap.java
+++ b/Essentials/src/net/ess3/storage/StorageObjectMap.java
@@ -5,16 +5,23 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
+import java.util.Enumeration;
import java.util.Locale;
import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
+import java.util.regex.Pattern;
import net.ess3.api.IEssentials;
import net.ess3.api.InvalidNameException;
import net.ess3.utils.Util;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.compress.archivers.zip.ZipFile;
+import org.apache.commons.io.IOUtils;
public abstract class StorageObjectMap<I> extends CacheLoader<String, I> implements IStorageObjectMap<I>
@@ -23,6 +30,7 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
private final transient File folder;
protected final transient Cache<String, I> cache = CacheBuilder.newBuilder().softValues().build(this);
protected final transient ConcurrentSkipListSet<String> keys = new ConcurrentSkipListSet<String>();
+ protected final transient ConcurrentSkipListMap<String, File> zippedfiles = new ConcurrentSkipListMap<String, File>();
public StorageObjectMap(final IEssentials ess, final String folderName)
{
@@ -51,20 +59,77 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
cache.invalidateAll();
for (String string : folder.list())
{
+ final File file = new File(folder, string);
+ if (!file.isFile() || !file.canRead())
+ {
+ continue;
+ }
+ if (string.endsWith(".yml"))
+ {
+ addFileToKeys(string.substring(0, string.length() - 4));
+ }
+ if (string.endsWith(".zip"))
+ {
+ addZipFile(file);
+ }
+ }
+ }
+
+ private void addFileToKeys(String filename)
+ {
+ try
+ {
+
+ final String name = Util.decodeFileName(filename);
+ keys.add(name.toLowerCase(Locale.ENGLISH));
+
+ }
+ catch (InvalidNameException ex)
+ {
+ ess.getLogger().log(Level.WARNING, "Invalid filename: " + filename, ex);
+ }
+ }
+
+ private final Pattern zipCheck = Pattern.compile("^[a-zA-Z0-9-]+\\.yml$");
+
+ private void addZipFile(File file)
+ {
+ try
+ {
+ ZipFile zipFile = new ZipFile(file);
try
{
- if (!string.endsWith(".yml"))
+ Enumeration<ZipArchiveEntry> entries = zipFile.getEntriesInPhysicalOrder();
+ while (entries.hasMoreElements())
{
- continue;
+ ZipArchiveEntry entry = entries.nextElement();
+ String name = entry.getName();
+ if (entry.isDirectory() || entry.getSize() == 0 || !zipCheck.matcher(name).matches())
+ {
+ continue;
+ }
+ try
+ {
+ String shortName = name.substring(0, name.length() - 4);
+ addFileToKeys(shortName);
+ final String decodedName = Util.decodeFileName(shortName).toLowerCase(Locale.ENGLISH);
+ zippedfiles.put(decodedName, file);
+ }
+ catch (InvalidNameException ex)
+ {
+ ess.getLogger().log(Level.WARNING, "Invalid filename " + name + " in " + file.getAbsoluteFile(), ex);
+ }
}
- final String name = Util.decodeFileName(string.substring(0, string.length() - 4));
- keys.add(name.toLowerCase(Locale.ENGLISH));
}
- catch (InvalidNameException ex)
+ finally
{
- ess.getLogger().log(Level.WARNING, "Invalid filename: " + string, ex);
+ zipFile.close();
}
}
+ catch (IOException ex)
+ {
+ ess.getLogger().log(Level.WARNING, "Error opening file " + file.getAbsolutePath(), ex);
+ }
}
});
}
@@ -98,13 +163,18 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
@Override
public void removeObject(final String name) throws InvalidNameException
{
- keys.remove(name.toLowerCase(Locale.ENGLISH));
- cache.invalidate(name.toLowerCase(Locale.ENGLISH));
+ String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
+ keys.remove(lowerCaseName);
+ cache.invalidate(lowerCaseName);
final File file = getStorageFile(name);
if (file.exists())
{
file.delete();
}
+ if (zippedfiles.containsKey(lowerCaseName))
+ {
+ zippedfiles.put(lowerCaseName, null);
+ }
}
@Override
@@ -126,7 +196,14 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
{
throw new InvalidNameException(new IOException("Folder does not exists: " + folder));
}
- return new File(folder, Util.sanitizeFileName(name) + ".yml");
+ String sanitizedFilename = Util.sanitizeFileName(name) + ".yml";
+ File file = new File(folder, sanitizedFilename);
+
+ if (!file.exists())
+ {
+ extractFileFromZip(name, sanitizedFilename, file);
+ }
+ return file;
}
@Override
@@ -134,4 +211,44 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
{
loadAllObjectsAsync();
}
+
+ private void extractFileFromZip(final String name, String sanitizedFilename, File file)
+ {
+ String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
+ File zipFile = zippedfiles.get(lowerCaseName);
+ if (zipFile != null)
+ {
+ try
+ {
+ ZipFile zip = new ZipFile(zipFile);
+ try
+ {
+ ZipArchiveEntry entry = zip.getEntry(sanitizedFilename);
+ if (entry != null)
+ {
+ try
+ {
+ IOUtils.copy(zip.getInputStream(entry), new FileOutputStream(file));
+ }
+ catch (IOException ex)
+ {
+ ess.getLogger().log(Level.WARNING, "Failed to write file: " + file.getAbsolutePath(), ex);
+ }
+ }
+ else
+ {
+ ess.getLogger().log(Level.WARNING, "File " + file.getAbsolutePath() + " not found in zip file " + zipFile.getAbsolutePath());
+ }
+ }
+ finally
+ {
+ zip.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ ess.getLogger().log(Level.WARNING, "File " + file.getAbsolutePath() + " could not be extracted from " + zipFile.getAbsolutePath(), ex);
+ }
+ }
+ }
}
diff --git a/Essentials/test/net/ess3/EssentialsTest.java b/Essentials/test/net/ess3/EssentialsTest.java
index 547b03f19..5eef12025 100644
--- a/Essentials/test/net/ess3/EssentialsTest.java
+++ b/Essentials/test/net/ess3/EssentialsTest.java
@@ -7,6 +7,7 @@ import java.util.List;
import java.util.logging.Logger;
import junit.framework.TestCase;
import net.ess3.api.IPlugin;
+import org.apache.commons.io.FileUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
@@ -82,17 +83,8 @@ public abstract class EssentialsTest extends TestCase
plugin = mock(IPlugin.class);
- File tmp;
- try
- {
- tmp = File.createTempFile("ess", "tmp");
- }
- catch (IOException ex)
- {
- throw new RuntimeException(ex);
- }
- tmp.deleteOnExit();
- when(plugin.getDataFolder()).thenReturn(tmp.getParentFile());
+ File folder = FileUtils.getTempDirectory();
+ when(plugin.getDataFolder()).thenReturn(folder);
when(world.getName()).thenReturn("world");
ess = new Essentials(server, logger, plugin);