package services.repository; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.typesafe.config.Config; import helpers.JsonLdConstants; import models.Resource; import org.apache.commons.codec.digest.DigestUtils; import org.apache.jena.atlas.RuntimeIOException; import org.elasticsearch.client.Client; import javax.annotation.Nonnull; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class FileRepository extends Repository implements Writable, Readable { private Client mClient; private TypeReference<HashMap<String, Object>> mMapType = new TypeReference<HashMap<String, Object>>() { }; private Path getPath() { return Paths.get(mConfiguration.getString("filerepo.dir")); } public FileRepository(Config aConfiguration) { super(aConfiguration); } /** * Add a new resource to the repository. * * @param aResource * @param aMetadata */ @Override public void addResource(@Nonnull final Resource aResource, Map<String, String> aMetadata) throws IOException { String id = aResource.getAsString(JsonLdConstants.ID); String encodedId = DigestUtils.sha256Hex(id); Path dir = Paths.get(getPath().toString(), aResource.getAsString(JsonLdConstants.TYPE)); Path file = Paths.get(dir.toString(), encodedId); if (!Files.exists(dir)) { Files.createDirectory(dir); } Files.write(file, aResource.toString().getBytes()); } @Override public void addResources(@Nonnull List<Resource> aResources, Map<String, String> aMetadata) throws IOException { throw new UnsupportedOperationException(); } /** * Get a Resource specified by the given identifier. * * @param aId * @return the Resource by the given identifier or null if no such Resource * exists. */ @Override public Resource getResource(@Nonnull String aId) { ObjectMapper objectMapper = new ObjectMapper(); Path resourceFile; try { resourceFile = getResourcePath(aId); Map<String, Object> resourceMap = objectMapper.readValue(resourceFile.toFile(), mMapType); return Resource.fromMap(resourceMap); } catch (IOException e) { return null; } } /** * Query all resources of a given type. * * @param aType The type of the resources to get * @return All resources of the given type as a List. */ @Override public List<Resource> getAll(@Nonnull String aType) { ArrayList<Resource> results = new ArrayList<>(); Path typeDir = Paths.get(getPath().toString(), aType); try (DirectoryStream<Path> resourceFiles = Files.newDirectoryStream(typeDir)) { ObjectMapper objectMapper = new ObjectMapper(); for (Path resourceFile : resourceFiles) { Map<String, Object> resourceMap; try { resourceMap = objectMapper.readValue(resourceFile.toFile(), mMapType); } catch (IOException ex) { ex.printStackTrace(); continue; } results.add(Resource.fromMap(resourceMap)); } } catch (IOException e) { throw new RuntimeIOException(e); } return results; } /** * Delete a Resource specified by the given identifier. * * @param aId * @param aMetadata * @return The resource that has been deleted. */ @Override public Resource deleteResource(@Nonnull String aId, Map<String, String> aMetadata) { Resource resource = this.getResource(aId); try { Files.delete(getResourcePath(aId)); } catch (IOException e) { return null; } return resource; } private Path getResourcePath(@Nonnull final String aId) throws IOException { String encodedId = DigestUtils.sha256Hex(aId); DirectoryStream.Filter<Path> directoryFilter = new DirectoryStream.Filter<Path>() { @Override public boolean accept(Path entry) throws IOException { return Files.isDirectory(entry); } }; try (DirectoryStream<Path> typeDirs = Files.newDirectoryStream(getPath(),directoryFilter)) { for (Path typeDir : typeDirs) { DirectoryStream.Filter<Path> fileFilter = new DirectoryStream.Filter<Path>() { @Override public boolean accept(Path entry) throws IOException { return (entry.getFileName().toString().equals(encodedId)); } }; try (DirectoryStream<Path> resourceFiles = Files.newDirectoryStream(typeDir, fileFilter)) { Iterator<Path> iterator = resourceFiles.iterator(); if (iterator.hasNext()) { return iterator.next(); } } } } throw new IOException(aId + " not found."); } }