package com.github.marschall.memoryfilesystem; import static java.nio.file.attribute.PosixFilePermission.GROUP_READ; import static java.nio.file.attribute.PosixFilePermission.OTHERS_READ; import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; import java.nio.file.attribute.FileAttributeView; import java.nio.file.attribute.FileOwnerAttributeView; import java.nio.file.attribute.PosixFilePermission; import java.text.Collator; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; class EnvironmentParser { private final Map<String, ?> env; private List<String> roots; EnvironmentParser(Map<String, ?> env) { this.env = env; } List<String> getRoots() { if (this.roots == null) { this.roots = this.parseStringProperty(MemoryFileSystemProperties.ROOTS_PROPERTY, false); if (this.roots == null) { this.roots = this.getDefaultRoots(); } else { this.validateRoots(this.roots); } } return this.roots; } List<String> getUserNames() { List<String> userNames = this.parseStringProperty(MemoryFileSystemProperties.USERS_PROPERTY, false); if (userNames == null) { return Collections.singletonList(this.getSystemUserName()); } else { return userNames; } } StringTransformer getStoreTransformer() { return this.getStringTranformer(MemoryFileSystemProperties.PATH_STORE_TRANSFORMER_PROPERTY); } StringTransformer getLookUpTransformer() { return this.getStringTranformer(MemoryFileSystemProperties.PATH_LOOKUP_TRANSFORMER_PROPERTY); } StringTransformer getStringTranformer(String property) { Object value = this.env.get(property); if (value != null) { if (value instanceof StringTransformer) { return (StringTransformer) value; } else { throw new IllegalArgumentException(property + " must be a " + StringTransformer.class + " but was " + value.getClass()); } } else { return StringTransformers.IDENTIY; } } Collator getCollator() { String property = MemoryFileSystemProperties.COLLATOR_PROPERTY; Object value = this.env.get(property); if (value != null) { if (value instanceof Collator) { return (Collator) value; } else { throw new IllegalArgumentException(property + " must be a " + Collator.class + " but was " + value.getClass()); } } else { return MemoryFileSystemProperties.caseSensitiveCollator(Locale.getDefault(), false); } } CharacterSet getForbiddenCharacters() { String property = MemoryFileSystemProperties.FORBIDDEN_CHARACTERS; Object value = this.env.get(property); if (value != null) { if (value instanceof Set) { Set<?> values = (Set<?>) value; if (values.isEmpty()) { return EmptyCharacterSet.INSTANCE; } else { char[] characters = new char[values.size()]; int i = 0; for (Object each : values) { if (each instanceof Character) { characters[i] = (Character) each; } else { throw new IllegalArgumentException(MemoryFileSystemProperties.FORBIDDEN_CHARACTERS + " values must be a " + String.class + " but was " + each); } i += 1; } return new ArrayCharacterSet(characters); } } else { throw new IllegalArgumentException(MemoryFileSystemProperties.FORBIDDEN_CHARACTERS + " must be a " + Set.class + " but was " + value.getClass()); } } else { return EmptyCharacterSet.INSTANCE; } } Set<Class<? extends FileAttributeView>> getAdditionalViews() { String property = MemoryFileSystemProperties.FILE_ATTRIBUTE_VIEWS_PROPERTY; Object value = this.env.get(property); if (value != null) { if (value instanceof Set) { Set<?> values = (Set<?>) value; if (values.isEmpty()) { return Collections.emptySet(); } else if (values.size() == 1) { Object viewName = values.iterator().next(); if (viewName instanceof String) { Class<? extends FileAttributeView> viewClass = FileAttributeViews.mapAttributeViewName((String) viewName); if (isOwnerSubclass(viewClass)) { Set<Class<? extends FileAttributeView>> views = new HashSet<>(values.size() + 1); views.add(viewClass); views.add(FileOwnerAttributeView.class); return views; } else { return Collections.<Class<? extends FileAttributeView>>singleton(viewClass); } } else { throw new IllegalArgumentException(property + " values must be a " + String.class + " but was " + viewName); } } else { Set<Class<? extends FileAttributeView>> views = new HashSet<>(values.size() + 1); for (Object viewName : values) { if (viewName instanceof String) { Class<? extends FileAttributeView> viewClass = FileAttributeViews.mapAttributeViewName((String) viewName); views.add(viewClass); if (isOwnerSubclass(viewClass)) { views.add(FileOwnerAttributeView.class); } } else { throw new IllegalArgumentException(property + " values must be a " + String.class + " but was " + viewName); } } return views; } } else { throw new IllegalArgumentException(property + " must be a " + Set.class + " but was " + value.getClass()); } } else { return Collections.emptySet(); } } private static boolean isOwnerSubclass(Class<? extends FileAttributeView> viewClass) { return viewClass != FileOwnerAttributeView.class && FileOwnerAttributeView.class.isAssignableFrom(viewClass); } Set<PosixFilePermission> getUmask() { String property = MemoryFileSystemProperties.UMASK_PROPERTY; Object value = this.env.get(property); if (value != null) { if (value instanceof Set) { Set<?> values = (Set<?>) value; if (values.isEmpty()) { return Collections.emptySet(); } else if (values.size() == 1) { Object permission = values.iterator().next(); if (permission instanceof PosixFilePermission) { return Collections.singleton((PosixFilePermission) permission); } else { throw new IllegalArgumentException(property + " values must be a " + PosixFilePermission.class + " but was " + permission); } } else { Set<PosixFilePermission> permissions = EnumSet.noneOf(PosixFilePermission.class); for (Object permission : values) { if (permission instanceof PosixFilePermission) { permissions.add((PosixFilePermission) permission); } else { throw new IllegalArgumentException(property + " values must be a " + PosixFilePermission.class + " but was " + permission); } } return permissions; } } else { throw new IllegalArgumentException(property + " must be a " + Set.class + " but was " + value.getClass()); } } else { return this.defaultPermssions(); } } Set<PosixFilePermission> defaultPermssions() { return EnumSet.of(OWNER_WRITE, OWNER_READ, GROUP_READ, OTHERS_READ); } StringTransformer getPrincipalNameTransfomer() { return this.getStringTranformer(MemoryFileSystemProperties.PRINCIPAL_TRANSFORMER_PROPERTY); } String getDefaultDirectory() { Object value = this.env.get(MemoryFileSystemProperties.CURRENT_WORKING_DIRECTORY_PROPERTY); if (value != null) { if (value instanceof String) { return (String) value; } else { throw new IllegalArgumentException(MemoryFileSystemProperties.CURRENT_WORKING_DIRECTORY_PROPERTY + " must be a " + String.class + " but was " + value.getClass()); } } else { return this.getRoots().get(0); } } String getSystemUserName() { return System.getProperty("user.name"); } List<String> getGroupNames() { List<String> groupNames = this.parseStringProperty(MemoryFileSystemProperties.GROUPS_PROPERTY, true); if (groupNames == null) { return Collections.singletonList(this.getSystemUserName()); } else { return groupNames; } } private List<String> parseStringProperty(String key, boolean allowEmpty) { Object value = this.env.get(key); if (value == null) { return null; } if (!(value instanceof List)) { throw new IllegalArgumentException("value of " + key + " must be an instance of " + List.class + " but was " + value.getClass()); } List<?> values = (List<?>) value; if (!allowEmpty && values.isEmpty()) { throw new IllegalArgumentException("value of " + key + " must not be empty"); } else if (values.size() == 1) { Object singleValue = values.get(0); if (singleValue instanceof String) { String stringValue = (String) singleValue; return Collections.singletonList(stringValue); } else { throw new IllegalArgumentException(key + " must be a String but was " + singleValue.getClass()); } } else { for (Object each : values) { if (each == null) { throw new IllegalArgumentException("each value of " + key + " must be a String but was null"); } else if (!(each instanceof String)) { throw new IllegalArgumentException("each value of " + key + " must be a String but was " + each.getClass()); } } @SuppressWarnings("unchecked") List<String> returnValue = (List<String>) values; return returnValue; } } private void validateRoots(List<String> roots) { if (roots.size() == 1) { String root = roots.get(0); if (!this.isUnixRoot(root) && !this.isWindowsRoot(root)) { throw this.invalidRoot(root); } } else { for (String root : roots) { if (!this.isWindowsRoot(root)) { throw this.invalidRoot(root); } } } } private IllegalArgumentException invalidRoot(String root) { return new IllegalArgumentException(MemoryFileSystemProperties.ROOTS_PROPERTY + " have to either be \"\" or \"[A-Z]:\\\" (mixing is not allowed)" + " \"" + root + "\"doesn't fit"); } private boolean isWindowsRoot(String root) { return root.length() == 3 && root.charAt(0) >= 'A' && root.charAt(0) <= 'Z' && root.endsWith(":\\"); } private boolean isUnixRoot(String root) { return MemoryFileSystemProperties.UNIX_ROOT.equals(root); } private List<String> getDefaultRoots() { return MemoryFileSystemProperties.DEFAULT_ROOTS; } String getSeparator() { Object property = this.env.get(MemoryFileSystemProperties.DEFAULT_NAME_SEPARATOR_PROPERTY); if (property == null) { return MemoryFileSystemProperties.DEFAULT_NAME_SEPARATOR; } else if (property instanceof String) { String separator = (String) property; this.validateSeparator(separator); return separator; } else { throw new IllegalArgumentException("the value of the property '" + MemoryFileSystemProperties.DEFAULT_NAME_SEPARATOR_PROPERTY + "' has to be of class " + String.class.getName() + " but was " + property.getClass().getName()); } } private void validateSeparator(String separator) { if (!MemoryFileSystemProperties.UNIX_SEPARATOR.equals(separator) && ! MemoryFileSystemProperties.WINDOWS_SEPARATOR.equals(separator)) { throw new IllegalArgumentException("only \"" + MemoryFileSystemProperties.UNIX_SEPARATOR + "\" and \"" + MemoryFileSystemProperties.WINDOWS_SEPARATOR + "\" are valid separators, \"" + separator + "\" is invalid"); } } boolean isSingleEmptyRoot() { return this.getRoots().size() == 1 && MemoryFileSystemProperties.UNIX_ROOT.equals(this.getRoots().get(0)); } }