package org.jbehave.core.io.rest; import static java.text.MessageFormat.format; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.jbehave.core.io.CodeLocations.codeLocationFromPath; import static org.jbehave.core.io.rest.filesystem.FilesystemUtils.fileNameWithoutExt; import static org.jbehave.core.io.rest.filesystem.FilesystemUtils.normalisedPathOf; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; import org.jbehave.core.io.StoryFinder; public abstract class IndexWithBreadcrumbs implements ResourceIndexer { private static final String EMPTY = ""; private static final String FULL_PATH = "{0}/{1}"; private RESTClient client; private ResourceNameResolver nameResolver; public IndexWithBreadcrumbs(RESTClient client, ResourceNameResolver nameResolver) { this.client = client; this.nameResolver = nameResolver; } public Map<String, Resource> indexResources(String rootURI) { String entity = get(uri(rootURI)); Map<String, Resource> index = createIndexFromEntity(rootURI, entity); addBreadcrumbs(index); return index; } public Map<String, Resource> indexResources(String rootURI, String rootPath, String syntax, String includes) { Map<String, Resource> index = createIndexFromPaths(rootURI, rootPath, syntax, includes); addBreadcrumbs(index); return index; } protected Map<String, Resource> createIndexFromPaths(String rootURI, String rootPath, String syntax, String includes) { Map<String, Resource> index = new HashMap<String, Resource>(); List<String> paths = new StoryFinder().findPaths( codeLocationFromPath(rootPath), includes, EMPTY); for (String path : paths) { addPath(rootURI, rootPath, fullPath(rootPath, path), syntax, index); } return index; } private void addPath(String rootURI, String rootPath, String path, String syntax, Map<String, Resource> index) { File file = new File(path); String name = resolveName(fileNameWithoutExt(file)); String parentName = parentName(file, rootPath); String uri = fullPath(rootURI, name); Resource resource = new Resource(uri, name, parentName); resource.setContent(contentOf(file)); if ( isNotBlank(syntax) ){ resource.setSyntax(syntax); } index.put(name, resource); if (parentName != null) { addPath(rootURI, rootPath, file.getParent(), syntax, index); } } private String parentName(File file, String rootPath) { File parent = file.getParentFile(); if (parent != null && !normalisedPathOf(parent).equals(rootPath)) { return resolveName(parent.getName()); } return null; } private String fullPath(String root, String path) { return format(FULL_PATH, root, path); } private String contentOf(File file) { if (file.isDirectory()) { return EMPTY; } try { return FileUtils.readFileToString(file); } catch (IOException e) { throw new RuntimeException( "Failed to read content of file " + file, e); } } protected void addBreadcrumbs(Map<String, Resource> index) { for (Resource resource : index.values()) { List<String> breadcrumbs = new ArrayList<String>(); collectBreadcrumbs(breadcrumbs, resource, index); resource.setBreadcrumbs(breadcrumbs); } } private void collectBreadcrumbs(List<String> breadcrumbs, Resource resource, Map<String, Resource> index) { if (resource.hasParent()) { String parentName = resource.getParentName(); breadcrumbs.add(0, parentName); Resource parent = index.get(parentName); if (parent != null) { collectBreadcrumbs(breadcrumbs, parent, index); } } } private String get(String uri) { return client.get(uri); } protected abstract Map<String, Resource> createIndexFromEntity( String rootURI, String entity); protected abstract String uri(String rootPath); protected String resolveName(String input){ return nameResolver.resolve(input); } public static class ToLowerCase implements ResourceNameResolver { public String resolve(String input) { return input.toLowerCase(); } } }