Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend url protocols #361

Merged
merged 7 commits into from Aug 19, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions core/src/main/java/cucumber/io/ClasspathIterable.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@

class ClasspathIterable implements Iterable<Resource> {
private final ClassLoader cl;
private final ResourceIteratorFactory resourceIteratorFactory;
private final String path;
private final String suffix;

public ClasspathIterable(ClassLoader cl, String path, String suffix) {
this.cl = cl;
this.resourceIteratorFactory = new DelegatingResourceIteratorFactory();
this.path = path;
this.suffix = suffix;
}
Expand All @@ -29,14 +31,7 @@ public Iterator<Resource> iterator() {
Enumeration<URL> resources = cl.getResources(path);
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
if (url.getProtocol().equals("jar")) {
String jarPath = filePath(url);
iterator.push(new ZipResourceIterator(jarPath, path, suffix));
} else {
File file = new File(getPath(url));
File rootDir = new File(file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - path.length()));
iterator.push(new FileResourceIterator(rootDir, file, suffix));
}
iterator.push(this.resourceIteratorFactory.createIterator(url, path, suffix));
}
return iterator;
} catch (IOException e) {
Expand All @@ -54,7 +49,7 @@ static boolean hasSuffix(String suffix, String name) {
return suffix == null || name.endsWith(suffix);
}

private static String getPath(URL url) {
static String getPath(URL url) {
try {
return URLDecoder.decode(url.getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cucumber.io;

import java.net.URL;
import java.util.Iterator;
import java.util.ServiceLoader;

import cucumber.runtime.CucumberException;


/**
* A {@link ResourceIteratorFactory} implementation which delegates to
* factories found by the ServiceLoader class.
*/
public class DelegatingResourceIteratorFactory implements ResourceIteratorFactory {

/**
* The delegates.
*/
private final Iterable<ResourceIteratorFactory> delegates;

/**
* The fallback resource iterator factory.
*/
private final ResourceIteratorFactory fallback;

/**
* Initializes a new instance of the DelegatingResourceIteratorFactory
* class.
*/
public DelegatingResourceIteratorFactory() {
this(new ZipThenFileResourceIteratorFallback());
}

/**
* Initializes a new instance of the DelegatingResourceIteratorFactory
* class with a fallback factory.
*
* @param fallback The fallback resource iterator factory to use when an
* appropriate one couldn't be found otherwise.
*/
public DelegatingResourceIteratorFactory(ResourceIteratorFactory fallback) {
delegates = ServiceLoader.load(ResourceIteratorFactory.class);
this.fallback = fallback;
}

@Override
public boolean isFactoryFor(URL url) {
for (ResourceIteratorFactory delegate : delegates) {
if (delegate.isFactoryFor(url)) {
return true;
}
}
return fallback.isFactoryFor(url);
}

@Override
public Iterator<Resource> createIterator(URL url, String path, String suffix) {
for (ResourceIteratorFactory delegate : delegates) {
if (delegate.isFactoryFor(url)) {
return delegate.createIterator(url, path, suffix);
}
}
if (fallback.isFactoryFor(url)) {
return fallback.createIterator(url, path, suffix);
} else {
throw new CucumberException("Fallback factory cannot handle URL: " + url);
}
}
}
39 changes: 39 additions & 0 deletions core/src/main/java/cucumber/io/FileResourceIteratorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cucumber.io;

import static cucumber.io.ClasspathIterable.getPath;

import java.io.File;
import java.net.URL;
import java.util.Iterator;

/**
* Factory which creates {@link FileResourceIterator}s.
*
* <p>{@link FileResourceIterator}s should be created for any cases where a
* URL's protocol isn't otherwise handled. Thus, {@link #isFactoryFor(URL)}
* will always return <code>true</code>. Because of this behavior, the
* <code>FileResourceIteratorFactory</code> should never be registered as a
* service implementation for {@link ResourceIteratorFactory} as it could
* easily hide other service implementations.</p>
*/
public class FileResourceIteratorFactory implements ResourceIteratorFactory {

/**
* Initializes a new instance of the FileResourceIteratorFactory class.
*/
public FileResourceIteratorFactory() {
// intentionally empty
}

@Override
public boolean isFactoryFor(URL url) {
return true;
}

@Override
public Iterator<Resource> createIterator(URL url, String path, String suffix) {
File file = new File(getPath(url));
File rootDir = new File(file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - path.length()));
return new FileResourceIterator(rootDir, file, suffix);
}
}
30 changes: 30 additions & 0 deletions core/src/main/java/cucumber/io/ResourceIteratorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package cucumber.io;

import java.net.URL;
import java.util.Iterator;

/**
* Factory contract for creating resource iterators.
*/
public interface ResourceIteratorFactory {

/**
* Gets a value indicating whether the factory can create iterators for the
* resource specified by the given URL.
*
* @param url The URL to check.
* @return True if the factory can create an iterator for the given URL.
*/
boolean isFactoryFor(URL url);

/**
* Creates an iterator for the given URL with the path and suffix.
*
* @param url The URL.
* @param path The path.
* @param suffix The suffix.
* @return The iterator over the resources designated by the URL, path, and
* suffix.
*/
Iterator<Resource> createIterator(URL url, String path, String suffix);
}
38 changes: 38 additions & 0 deletions core/src/main/java/cucumber/io/ZipResourceIteratorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package cucumber.io;

import static cucumber.io.ClasspathIterable.filePath;

import java.io.IOException;
import java.net.URL;
import java.util.Iterator;

import cucumber.runtime.CucumberException;

/**
* Factory which creates {@link ZipResourceIterator}s for URL's with the "jar"
* protocol.
*/
public class ZipResourceIteratorFactory implements ResourceIteratorFactory {

/**
* Initializes a new instance of the ZipResourceIteratorFactory class.
*/
public ZipResourceIteratorFactory() {
// intentionally empty
}

@Override
public boolean isFactoryFor(URL url) {
return "jar".equals(url.getProtocol());
}

@Override
public Iterator<Resource> createIterator(URL url, String path, String suffix) {
try {
String jarPath = filePath(url);
return new ZipResourceIterator(jarPath, path, suffix);
} catch (IOException e) {
throw new CucumberException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cucumber.io;

import java.net.URL;
import java.util.Iterator;

/**
* Resource iterator factory implementation which acts as a fallback when no
* other factories are found.
*/
public class ZipThenFileResourceIteratorFallback implements ResourceIteratorFactory {
/**
* The file resource iterator factory.
*/
private final FileResourceIteratorFactory fileResourceIteratorFactory;

/**
* The ZIP resource iterator factory.
*/
private final ZipResourceIteratorFactory zipResourceIteratorFactory;


/**
* Initializes a new instance of the ZipThenFileResourceIteratorFallback
* class.
*/
public ZipThenFileResourceIteratorFallback() {
fileResourceIteratorFactory = new FileResourceIteratorFactory();
zipResourceIteratorFactory = new ZipResourceIteratorFactory();
}

@Override
public boolean isFactoryFor(URL url) {
return zipResourceIteratorFactory.isFactoryFor(url) || fileResourceIteratorFactory.isFactoryFor(url);
}

@Override
public Iterator<Resource> createIterator(URL url, String path, String suffix) {
if (zipResourceIteratorFactory.isFactoryFor(url)) {
return zipResourceIteratorFactory.createIterator(url, path, suffix);
} else {
return fileResourceIteratorFactory.createIterator(url, path, suffix);
}
}
}
2 changes: 1 addition & 1 deletion core/src/main/java/cucumber/table/DataTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public List<List<String>> raw() {
}

public <T> T convert(Type type) {
return tableConverter.convert(type, this);
return tableConverter.<T>convert(type, this);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cucumber.io;

import static org.junit.Assert.assertTrue;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;

import org.junit.Test;

import cucumber.io.TestResourceIteratorFactory.TestResourceIterator;


public class DelegatingResourceIteratorFactoryTest {

@Test
public void should_load_test_resource_iterator() throws MalformedURLException {
ResourceIteratorFactory factory = new DelegatingResourceIteratorFactory();
URL url = new URL("file:///this/is/only/a/test");

assertTrue(factory.isFactoryFor(url));

Iterator<Resource> iterator = factory.createIterator(url, "test", "test");

assertTrue(iterator instanceof TestResourceIterator);
}
}
8 changes: 7 additions & 1 deletion core/src/test/java/cucumber/io/ResourceLoaderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class ResourceLoaderTest {
private final File dir = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getFile());
private final File dir;

public ResourceLoaderTest() throws UnsupportedEncodingException {
dir = new File(URLDecoder.decode(getClass().getProtectionDomain().getCodeSource().getLocation().getFile(), "UTF-8"));
}

@Test
public void loads_resources_from_filesystem_dir() {
Expand Down
43 changes: 43 additions & 0 deletions core/src/test/java/cucumber/io/TestResourceIteratorFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package cucumber.io;

import java.net.URL;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class TestResourceIteratorFactory implements ResourceIteratorFactory
{
/**
* Initializes a new instance of the TestResourceIteratorFactory class.
*/
public TestResourceIteratorFactory() {
// intentionally empty
}

@Override
public boolean isFactoryFor(URL url) {
return "file".equals(url.getProtocol()) && url.getPath().endsWith("test");
}

@Override
public Iterator<Resource> createIterator(URL url, String path, String suffix) {
return new TestResourceIterator();
}

public static final class TestResourceIterator implements Iterator<Resource> {

@Override
public boolean hasNext() {
return false;
}

@Override
public Resource next() {
throw new NoSuchElementException();
}

@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cucumber.io.TestResourceIteratorFactory