Пример #1
0
  public static void main(String[] args) throws Exception {
    System.out.println("Starting Cache Client...");
    int bucket;

    List<CacheServiceInterface> serverlist = new ArrayList<CacheServiceInterface>();
    serverlist.add(new DistributedCacheService("http://localhost:3000"));
    serverlist.add(new DistributedCacheService("http://localhost:3001"));
    serverlist.add(new DistributedCacheService("http://localhost:3002"));

    CharSequence val;
    for (int key = 1; key <= 10; key++) {
      val = generateRandomChar();
      bucket =
          Hashing.consistentHash(
              Hashing.md5().hashString(Integer.toString(key)), serverlist.size());
      serverlist.get(bucket).put(key, val.toString());

      System.out.println("put (key " + key + " and value " + val + ")" + " in bucket " + bucket);
    }
    for (int key = 1; key <= 10; key++) {
      bucket =
          Hashing.consistentHash(
              Hashing.md5().hashString(Integer.toString(key)), serverlist.size());
      System.out.println(
          "get (key "
              + key
              + " and value "
              + serverlist.get(bucket).get(key)
              + ")"
              + "from bucket "
              + bucket);
    }

    System.out.println("Exiting Cache Client...");
  }
Пример #2
0
  public static void main(String[] args) throws Exception {
    System.out.println("Starting Cache Client...");
    String[] value = {
      "0",
      "Ferrari 250 GTO",
      "Ferrari 250 Testa Rossa",
      "Jaguar XJ13",
      "Mercedes-Benz SLR McLaren",
      "Ferrari 330 P4",
      "Maybach Exelero",
      "Rolls-Royce Hyperion",
      "Lamborghini Veneno",
      "Zenvo ST1",
      "Audi Le Mans Concept",
      " McLaren X-1 Concept",
      "Koenigsegg CCXR Trevita"
    };
    List<DistributedCacheService> server = new ArrayList<DistributedCacheService>();
    server.add(new DistributedCacheService("http://localhost:3000"));
    server.add(new DistributedCacheService("http://localhost:3001"));
    server.add(new DistributedCacheService("http://localhost:3002"));

    System.out.println(" ----------------------Putting values to server------------------");
    for (int putkey = 1; putkey <= 12; putkey++) {
      int bucket =
          Hashing.consistentHash(Hashing.md5().hashString(Integer.toString(putkey)), server.size());
      server.get(bucket).put(putkey, value[putkey]);
      System.out.println(
          "The key value pair "
              + putkey
              + "-"
              + value[putkey]
              + " is assigned to server "
              + bucket);
    }
    System.out.println(" ----------------------Getting values from server------------------");
    for (int getkey = 1; getkey <= 12; getkey++) {
      int bucket =
          Hashing.consistentHash(Hashing.md5().hashString(Integer.toString(getkey)), server.size());
      System.out.println(
          "The key value pair "
              + getkey
              + "-"
              + server.get(bucket).get(getkey)
              + " is received to server "
              + bucket);
    }
    System.out.println(" ------------------------------Terminated---------------------------");
  }
  public static void main(String[] args) throws IOException {
    Closer closer = Closer.create();
    // copy a file
    File origin = new File("join_temp");
    File copy = new File("target_temp");

    try {
      BufferedReader reader = new BufferedReader(new FileReader("join_temp"));
      BufferedWriter writer = new BufferedWriter(new FileWriter("target_temp"));

      closer.register(reader);
      closer.register(writer);

      String line;

      while ((line = reader.readLine()) != null) {
        writer.write(line);
      }
    } catch (IOException e) {
      throw closer.rethrow(e);
    } finally {
      closer.close();
    }

    Files.copy(origin, copy);

    File moved = new File("moved");

    // moving renaming
    Files.move(copy, moved);

    // working files as string
    List<String> lines = Files.readLines(origin, Charsets.UTF_8);

    HashCode hashCode = Files.hash(origin, Hashing.md5());
    System.out.println(hashCode);

    // file write and append
    String hamlet = "To be, or not to be it is a question\n";
    File write_and_append = new File("write_and_append");

    Files.write(hamlet, write_and_append, Charsets.UTF_8);

    Files.append(hamlet, write_and_append, Charsets.UTF_8);

    //        write_and_append.deleteOnExit();

    Files.write("OverWrite the file", write_and_append, Charsets.UTF_8);

    // ByteSource ByteSink
    ByteSource fileBytes = Files.asByteSource(write_and_append);
    byte[] readBytes = fileBytes.read();
    // equals to pre line -> Files.toByteArray(write_and_append) == readBytes

    ByteSink fileByteSink = Files.asByteSink(write_and_append);
    fileByteSink.write(Files.toByteArray(write_and_append));

    BaseEncoding base64 = BaseEncoding.base64();
    System.out.println(base64.encode("123456".getBytes()));
  }
  @Test
  public void testOnConnected() throws Exception {
    String password = "******";

    when(userService.getPassword()).thenReturn(password);
    instance.connect();

    botStartedFuture.get(TIMEOUT, TIMEOUT_UNIT);

    CountDownLatch latch = new CountDownLatch(1);
    doAnswer(
            invocation -> {
              latch.countDown();
              return null;
            })
        .when(outputIrc)
        .joinChannel(DEFAULT_CHANNEL_NAME);

    mockTaskService();
    instance.connectionStateProperty().set(ConnectionState.CONNECTED);

    String md5Password = Hashing.md5().hashString(password, StandardCharsets.UTF_8).toString();
    verify(outputIrc).message("NICKSERV", String.format("IDENTIFY %s", md5Password));

    assertTrue("Channel has not been joined within timeout", latch.await(TIMEOUT, TIMEOUT_UNIT));
  }
Пример #5
0
 public HashCode getOutputHash(FileHashCache fileHashCache) throws IOException {
   Hasher hasher = Hashing.md5().newHasher();
   for (Path path : getRecordedPaths()) {
     hasher.putBytes(fileHashCache.get(path).asBytes());
   }
   return hasher.hash();
 }
 /** Walk project references recursively, adding thrift files to the provided list. */
 List<File> getRecursiveThriftFiles(MavenProject project, String outputDirectory, List<File> files)
     throws IOException {
   HashFunction hashFun = Hashing.md5();
   if (dependencyIncludes.contains(project.getArtifactId())) {
     File dir = new File(new File(project.getFile().getParent(), "target"), outputDirectory);
     if (dir.exists()) {
       URI baseDir = getFileURI(dir);
       for (File f : findThriftFilesInDirectory(dir)) {
         URI fileURI = getFileURI(f);
         String relPath = baseDir.relativize(fileURI).getPath();
         File destFolder = getResourcesOutputDirectory();
         destFolder.mkdirs();
         File destFile = new File(destFolder, relPath);
         if (!destFile.exists()
             || (destFile.isFile()
                 && !Files.hash(f, hashFun).equals(Files.hash(destFile, hashFun)))) {
           getLog()
               .info(
                   format("copying %s to %s", f.getCanonicalPath(), destFile.getCanonicalPath()));
           copyFile(f, destFile);
         }
         files.add(destFile);
       }
     }
   }
   Map<String, MavenProject> refs = project.getProjectReferences();
   for (String name : refs.keySet()) {
     getRecursiveThriftFiles(refs.get(name), outputDirectory, files);
   }
   return files;
 }
Пример #7
0
  public void sendUpUserMessage() throws IOException {
    Properties properties = new Properties();
    properties.put("metadata.broker.list", "10.1.3.55:9092,10.1.3.56:9092,10.1.3.59:9092");
    properties.put("serializer.class", "kafka.serializer.StringEncoder");
    ProducerConfig producerConfig = new ProducerConfig(properties);
    kafka.javaapi.producer.Producer<String, String> producer =
        new kafka.javaapi.producer.Producer<String, String>(producerConfig);

    InputStream in = this.getClass().getResourceAsStream("/upusers.csv");
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    String line = null;
    while ((line = reader.readLine()) != null) {
      // System.out.println(line);
      ArrayList<String> list =
          new ArrayList<String>(Arrays.asList(line.replace(";NULL", "").split(",")));
      if (list.size() != 0) {
        list.remove(0);
        String uid = list.remove(0);
        String nline =
            Hashing.md5()
                    .hashString(
                        uid + System.currentTimeMillis() + new Random().nextLong(), Charsets.UTF_8)
                + ","
                + Joiner.on(",").join(list.toArray()).toString();
        // String nline = Joiner.on(",").join(list.toArray()).toString();
        KeyedMessage<String, String> message = new KeyedMessage<String, String>(TOPIC, nline);
        producer.send(message);
        // System.out.println(nline);
        // System.out.println(nline);
      }
    }
  }
Пример #8
0
 /** Get a Md5 string which is similar to OS Md5sum */
 public static String md5(File file) {
   try {
     HashCode hc = Files.hash(file, Hashing.md5());
     return toHex(hc.asBytes());
   } catch (Exception e) {
     throw new RuntimeException(e);
   }
 }
Пример #9
0
 static {
   HASH_FUNCTIONS.put("md5", Hashing.md5());
   HASH_FUNCTIONS.put("sha1", Hashing.sha1());
   HASH_FUNCTIONS.put("sha256", Hashing.sha256());
   HASH_FUNCTIONS.put("sha512", Hashing.sha512());
   HASH_FUNCTIONS.put("murmur3_32", Hashing.murmur3_32());
   HASH_FUNCTIONS.put("murmur3_128", Hashing.murmur3_128());
 }
Пример #10
0
  public Crypto(String passphrase) {
    byte[] key = Hashing.md5().hashString(passphrase).asBytes();

    keySpec = new SecretKeySpec(key, CIPHER_ALGORITHM);

    try {
      cipher = Cipher.getInstance(CIPHER_TRANSFORMATION, "BC");
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  @Test
  public void mappedServersTest() {

    Map<Integer, String> servers = new HashMap<>();
    servers.put(0, "server0");
    servers.put(1, "server1");

    HashFunction md5 = Hashing.md5();
    List<PartitionEntry> triggers = generateTriggers(3, 1000);

    Map<Integer, String> newPartition;
    Map<Integer, String> oldPartition;

    print("initial - test 2 servers " + servers.toString());
    newPartition = new HashMap<>();
    for (PartitionEntry trigger : triggers) {
      newPartition.put(
          trigger.hashCode(),
          servers.get(Hashing.consistentHash(md5.hashInt(trigger.hashCode()), 2)));
    }

    for (int buckets = 3; buckets < 10; buckets++) {

      servers.put(buckets - 1, "server" + (buckets - 1));
      print("test " + buckets + " servers " + servers.toString());

      oldPartition = newPartition;
      newPartition = new HashMap<>();
      for (PartitionEntry trigger : triggers) {
        newPartition.put(
            trigger.hashCode(),
            servers.get(Hashing.consistentHash(md5.hashInt(trigger.hashCode()), buckets)));
      }

      int changes = comparePartitions(oldPartition, newPartition);
      print(
          "Changes from "
              + (buckets - 1)
              + "  to "
              + buckets
              + " servers: "
              + changes
              + " of "
              + oldPartition.size());
      print("" + (((float) changes / (float) oldPartition.size()) * 100) + " % moved");
      print(
          "K("
              + oldPartition.size()
              + ")/n("
              + buckets
              + "): "
              + ((float) oldPartition.size() / (float) buckets));
    }
  }
 private void redirectToLoginDialog(final HttpServletResponse res) throws Exception {
   final String hash = Hashing.md5().hashString("aWl0cnVzdGl0").toString();
   res.sendRedirect(
       this.fbOauthUrl
           + "?client_id="
           + this.fbAppId
           + "&redirect_uri="
           + this.fbLoginUrl
           + "&state="
           + hash);
 }
Пример #13
0
/**
 * Constants for the Node Layer.
 *
 * @author Sebastian Graf, University of Konstanz
 */
public interface IConstants {

  /** Static to determine key for root node. */
  public static final long ROOT_NODE = 0;
  /** Static to determine key for null node. */
  public static final long NULL_NODE = -1;

  /** Hashing function for nodes. */
  public static final HashFunction HF = Hashing.md5();

  /** Static type key for normal txpes. */
  public static final int TYPE_KEY = NamePageHash.generateHashForString("xs:untyped");
}
 private boolean haveSameContents(File file, final JarFile jar, final JarEntry entry)
     throws IOException {
   HashFunction hashFun = Hashing.md5();
   HashCode fileHash = Files.hash(file, hashFun);
   HashCode streamHash =
       ByteStreams.hash(
           new InputSupplier<InputStream>() {
             public InputStream getInput() throws IOException {
               return jar.getInputStream(entry);
             }
           },
           hashFun);
   return fileHash.equals(streamHash);
 }
Пример #15
0
  private void deserializeRule(DeserializationContext context, Build.Rule rulePb)
      throws PackageDeserializationException, InterruptedException {
    Location ruleLocation = EmptyLocation.INSTANCE;
    RuleClass ruleClass = packageDeserializationEnvironment.getRuleClass(rulePb, ruleLocation);
    Map<String, ParsedAttributeValue> attributeValues = new HashMap<>();
    AttributesToDeserialize attrToDeserialize =
        packageDeserializationEnvironment.attributesToDeserialize();

    Hasher hasher = Hashing.md5().newHasher();
    for (Build.Attribute attrPb : rulePb.getAttributeList()) {
      Type<?> type = ruleClass.getAttributeByName(attrPb.getName()).getType();
      attributeValues.put(attrPb.getName(), deserializeAttribute(type, attrPb));
      if (attrToDeserialize.addSyntheticAttributeHash) {
        // TODO(bazel-team): This might give false positives because of explicit vs implicit.
        hasher.putBytes(attrPb.toByteArray());
      }
    }
    AttributeContainerWithoutLocation attributeContainer =
        new AttributeContainerWithoutLocation(ruleClass, hasher.hash());

    Label ruleLabel = deserializeLabel(rulePb.getName());
    try {
      Rule rule =
          createRuleWithParsedAttributeValues(
              ruleClass,
              ruleLabel,
              context.packageBuilder,
              ruleLocation,
              attributeValues,
              NullEventHandler.INSTANCE,
              attributeContainer);
      context.packageBuilder.addRule(rule);

      // Remove the attribute after it is added to package in order to pass the validations
      // and be able to compute all the outputs.
      if (attrToDeserialize != DESERIALIZE_ALL_ATTRS) {
        for (String attrName : attributeValues.keySet()) {
          Attribute attribute = ruleClass.getAttributeByName(attrName);
          if (!(attrToDeserialize.shouldKeepAttributeWithName.apply(attrName)
              || BuildType.isLabelType(attribute.getType()))) {
            attributeContainer.clearIfNotLabel(attrName);
          }
        }
      }

      Preconditions.checkState(!rule.containsErrors());
    } catch (NameConflictException | LabelSyntaxException e) {
      throw new PackageDeserializationException(e);
    }
  }
Пример #16
0
 public static String getImageUploadIdentifier(String s, long l, int i) {
   s =
       String.valueOf(
           Hashing.md5()
               .hashUnencodedChars(
                   (new StringBuilder(String.valueOf(s).length() + 21))
                       .append(s)
                       .append("@")
                       .append(l)
                       .toString()));
   return (new StringBuilder(String.valueOf(s).length() + 12))
       .append(s)
       .append("/")
       .append(i)
       .toString();
 }
Пример #17
0
  public static void main(String[] args) throws Exception {
    System.out.println("Starting Cache Client...");
    ArrayList<CacheServiceInterface> servers = new ArrayList<>();
    servers.add(new DistributedCacheService("http://localhost:3000"));
    servers.add(new DistributedCacheService("http://localhost:3001"));
    servers.add(new DistributedCacheService("http://localhost:3002"));

    ConsistentHash hash = new ConsistentHash(Hashing.md5(), 3, servers);
    for (long i = 1; i <= 10; i++) {
      String aux = Character.toString((char) ('a' + i - 1));
      hash.get(i).put(i, aux);
      int bucket = servers.indexOf(hash.get(i));
      System.out.println(
          i + " routed to: " + ((DistributedCacheService) servers.get(bucket)).getUrl());
    }
    for (long i = 1; i <= 10; i++) {
      System.out.println("GET(" + i + ") ==> " + hash.get(i).get(i));
    }

    System.out.println("Existing Cache Client...");
  }
 /**
  * 创建注册中心.
  *
  * @param connectString 注册中心连接字符串
  * @param namespace 注册中心命名空间
  * @param digest 注册中心凭证
  * @return 注册中心对象
  */
 public static CoordinatorRegistryCenter createCoordinatorRegistryCenter(
     final String connectString, final String namespace, final Optional<String> digest) {
   Hasher hasher =
       Hashing.md5()
           .newHasher()
           .putString(connectString, Charsets.UTF_8)
           .putString(namespace, Charsets.UTF_8);
   if (digest.isPresent()) {
     hasher.putString(digest.get(), Charsets.UTF_8);
   }
   HashCode hashCode = hasher.hash();
   if (regCenterMap.containsKey(hashCode)) {
     return regCenterMap.get(hashCode);
   }
   ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(connectString, namespace);
   if (digest.isPresent()) {
     zkConfig.setDigest(digest.get());
   }
   CoordinatorRegistryCenter result = new ZookeeperRegistryCenter(zkConfig);
   result.init();
   regCenterMap.putIfAbsent(hashCode, result);
   return result;
 }
 private Statement generateStatement(final String sql, final String dataSourceName)
     throws SQLException {
   HashCode hashCode =
       Hashing.md5()
           .newHasher()
           .putString(sql, Charsets.UTF_8)
           .putString(dataSourceName, Charsets.UTF_8)
           .hash();
   if (cachedRoutedStatements.containsKey(hashCode)) {
     return cachedRoutedStatements.get(hashCode);
   }
   Connection connection = shardingConnection.getConnection(dataSourceName);
   Statement result;
   if (0 == resultSetHoldability) {
     result = connection.createStatement(resultSetType, resultSetConcurrency);
   } else {
     result =
         connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
   }
   replayMethodsInvocation(result);
   cachedRoutedStatements.put(hashCode, result);
   return result;
 }
  @Override
  public Blob getBlob(final String container, final String key) {
    BlobBuilder builder = blobBuilders.get();
    builder.name(key);
    File file = getFileForBlobKey(container, key);
    ByteSource byteSource;

    if (getDirectoryBlobSuffix(key) != null) {
      logger.debug("%s - %s is a directory", container, key);
      byteSource = ByteSource.empty();
    } else {
      byteSource = Files.asByteSource(file);
    }
    try {
      String cacheControl = null;
      String contentDisposition = null;
      String contentEncoding = null;
      String contentLanguage = null;
      String contentType = null;
      HashCode hashCode = null;
      Date expires = null;
      ImmutableMap.Builder<String, String> userMetadata = ImmutableMap.builder();

      UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(file.toPath());
      if (view != null) {
        Set<String> attributes = ImmutableSet.copyOf(view.list());

        cacheControl = readStringAttributeIfPresent(view, attributes, XATTR_CACHE_CONTROL);
        contentDisposition =
            readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_DISPOSITION);
        contentEncoding = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_ENCODING);
        contentLanguage = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_LANGUAGE);
        contentType = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_TYPE);
        if (contentType == null && autoDetectContentType) {
          contentType = probeContentType(file.toPath());
        }
        if (attributes.contains(XATTR_CONTENT_MD5)) {
          ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_CONTENT_MD5));
          view.read(XATTR_CONTENT_MD5, buf);
          hashCode = HashCode.fromBytes(buf.array());
        }
        if (attributes.contains(XATTR_EXPIRES)) {
          ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_EXPIRES));
          view.read(XATTR_EXPIRES, buf);
          buf.flip();
          expires = new Date(buf.asLongBuffer().get());
        }
        for (String attribute : attributes) {
          if (!attribute.startsWith(XATTR_USER_METADATA_PREFIX)) {
            continue;
          }
          String value = readStringAttributeIfPresent(view, attributes, attribute);
          userMetadata.put(attribute.substring(XATTR_USER_METADATA_PREFIX.length()), value);
        }

        builder
            .payload(byteSource)
            .cacheControl(cacheControl)
            .contentDisposition(contentDisposition)
            .contentEncoding(contentEncoding)
            .contentLanguage(contentLanguage)
            .contentLength(byteSource.size())
            .contentMD5(hashCode)
            .contentType(contentType)
            .expires(expires)
            .userMetadata(userMetadata.build());
      } else {
        builder
            .payload(byteSource)
            .contentLength(byteSource.size())
            .contentMD5(byteSource.hash(Hashing.md5()).asBytes());
      }
    } catch (IOException e) {
      throw Throwables.propagate(e);
    }
    Blob blob = builder.build();
    blob.getMetadata().setContainer(container);
    blob.getMetadata().setLastModified(new Date(file.lastModified()));
    blob.getMetadata().setSize(file.length());
    if (blob.getPayload().getContentMetadata().getContentMD5() != null)
      blob.getMetadata()
          .setETag(
              base16().lowerCase().encode(blob.getPayload().getContentMetadata().getContentMD5()));
    return blob;
  }
  @Override
  public String putBlob(final String containerName, final Blob blob) throws IOException {
    String blobKey = blob.getMetadata().getName();
    Payload payload = blob.getPayload();
    filesystemContainerNameValidator.validate(containerName);
    filesystemBlobKeyValidator.validate(blobKey);
    if (getDirectoryBlobSuffix(blobKey) != null) {
      return putDirectoryBlob(containerName, blob);
    }
    File outputFile = getFileForBlobKey(containerName, blobKey);
    // TODO: should we use a known suffix to filter these out during list?
    String tmpBlobName = blobKey + "-" + UUID.randomUUID();
    File tmpFile = getFileForBlobKey(containerName, tmpBlobName);
    Path tmpPath = tmpFile.toPath();
    HashingInputStream his = null;
    try {
      Files.createParentDirs(tmpFile);
      his = new HashingInputStream(Hashing.md5(), payload.openStream());
      long actualSize = Files.asByteSink(tmpFile).writeFrom(his);
      Long expectedSize = blob.getMetadata().getContentMetadata().getContentLength();
      if (expectedSize != null && actualSize != expectedSize) {
        throw new IOException(
            "Content-Length mismatch, actual: " + actualSize + " expected: " + expectedSize);
      }
      HashCode actualHashCode = his.hash();
      HashCode expectedHashCode = payload.getContentMetadata().getContentMD5AsHashCode();
      if (expectedHashCode != null && !actualHashCode.equals(expectedHashCode)) {
        throw new IOException(
            "MD5 hash code mismatch, actual: " + actualHashCode + " expected: " + expectedHashCode);
      }
      payload.getContentMetadata().setContentMD5(actualHashCode);

      if (outputFile.exists()) {
        delete(outputFile);
      }

      UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(tmpPath);
      if (view != null) {
        try {
          view.write(XATTR_CONTENT_MD5, ByteBuffer.wrap(actualHashCode.asBytes()));
          writeCommonMetadataAttr(view, blob);
        } catch (IOException e) {
          logger.debug("xattrs not supported on %s", tmpPath);
        }
      }

      setBlobAccess(containerName, tmpBlobName, BlobAccess.PRIVATE);

      if (!tmpFile.renameTo(outputFile)) {
        throw new RuntimeException("Could not rename file " + tmpFile + " to " + outputFile);
      }

      return base16().lowerCase().encode(actualHashCode.asBytes());
    } catch (IOException ex) {
      if (tmpFile != null) {
        try {
          delete(tmpFile);
        } catch (IOException e) {
          logger.debug("Could not delete %s: %s", tmpFile, e);
        }
      }
      throw ex;
    } finally {
      closeQuietly(his);
      if (payload != null) {
        payload.release();
      }
    }
  }
public class NitroOnDemandLocationGeneratorTest {

  private static final String ON_DEMAND_IMI = "on_demand_imi";
  private static final int VIDEO_BITRATE = 1500000;

  private static final Function<GenreType, String> GENRE_TO_HREF =
      new Function<GenreType, String>() {
        @Override
        public String apply(GenreType input) {
          return input.getHref();
        }
      };

  private static final Function<GenreType, String> GENRE_TO_TYPE =
      new Function<GenreType, String>() {
        @Override
        public String apply(GenreType input) {
          return input.getType();
        }
      };

  private IdGenerator idGenerator = new NitroIdGenerator(Hashing.md5());

  private final OnDemandLocationGenerator generator =
      new NitroOnDemandLocationGenerator(idGenerator);

  @Test
  public void testNonPublisherSpecificFields() {
    ItemOnDemandHierarchy onDemandHierarchy = hierarchyFrom(createNitroFilm(true));

    ExtendedOnDemandProgramType onDemand =
        (ExtendedOnDemandProgramType) generator.generate(onDemandHierarchy, ON_DEMAND_IMI);

    assertEquals("P0DT1H30M0.000S", onDemand.getPublishedDuration().toString());
    assertEquals("2012-07-03T00:00:00Z", onDemand.getStartOfAvailability().toString());
    assertEquals("2013-07-17T00:00:00Z", onDemand.getEndOfAvailability().toString());
    assertTrue(onDemand.getFree().isValue());

    InstanceDescriptionType instanceDesc = onDemand.getInstanceDescription();

    CaptionLanguageType captionLanguage =
        Iterables.getOnlyElement(instanceDesc.getCaptionLanguage());

    assertTrue(captionLanguage.isClosed());
    assertEquals(captionLanguage.getValue(), "en");

    List<SignLanguageType> signLanguages = instanceDesc.getSignLanguage();
    SignLanguageType signLanguageType = Iterables.getOnlyElement(signLanguages);
    assertEquals("bfi", signLanguageType.getValue());

    AVAttributesType avAttributes = instanceDesc.getAVAttributes();
    AudioAttributesType audioAttrs = Iterables.getOnlyElement(avAttributes.getAudioAttributes());

    assertEquals("urn:mpeg:mpeg7:cs:AudioPresentationCS:2001:3", audioAttrs.getMixType().getHref());

    VideoAttributesType videoAttrs = avAttributes.getVideoAttributes();

    assertEquals(Integer.valueOf(1280), videoAttrs.getHorizontalSize());
    assertEquals(Integer.valueOf(720), videoAttrs.getVerticalSize());
    assertEquals("16:9", Iterables.getOnlyElement(videoAttrs.getAspectRatio()).getValue());

    assertEquals(BigInteger.valueOf(VIDEO_BITRATE), avAttributes.getBitRate().getValue());
    assertTrue(avAttributes.getBitRate().isVariable());

    UniqueIDType otherId = Iterables.getOnlyElement(instanceDesc.getOtherIdentifier());
    assertEquals("b020tm1g", otherId.getValue());
    assertEquals("epid.bbc.co.uk", otherId.getAuthority());
  }

  @Test
  public void testNitroSpecificFields() {
    Film film = createNitroFilm(false);
    ItemOnDemandHierarchy hierarchy = hierarchyFrom(film);
    String versionCrid = idGenerator.generateVersionCrid(hierarchy.item(), hierarchy.version());
    String onDemandImi =
        idGenerator.generateOnDemandImi(
            hierarchy.item(), hierarchy.version(), hierarchy.encoding(), hierarchy.location());

    ExtendedOnDemandProgramType onDemand =
        (ExtendedOnDemandProgramType) generator.generate(hierarchy, onDemandImi);

    assertEquals("http://nitro.bbc.co.uk/services/youview", onDemand.getServiceIDRef());
    assertEquals(versionCrid, onDemand.getProgram().getCrid());
    assertEquals(onDemandImi, onDemand.getInstanceMetadataId());

    InstanceDescriptionType instanceDesc = onDemand.getInstanceDescription();

    AVAttributesType avAttributes = instanceDesc.getAVAttributes();
    List<AudioAttributesType> audioAttributes = avAttributes.getAudioAttributes();
    AudioAttributesType audioAttribute = Iterables.getOnlyElement(audioAttributes);
    AudioLanguageType audioLanguage = audioAttribute.getAudioLanguage();

    assertEquals("urn:tva:metadata:cs:AudioPurposeCS:2007:1", audioLanguage.getPurpose());
    assertEquals(true, audioLanguage.isSupplemental());
    assertEquals("dubbed", audioLanguage.getType());
  }

  @Test
  public void testGaelicLanguageIsSetForSubtitlesOnAlbaChannel() {
    Film film = createAlbaNitroFilm();
    ExtendedOnDemandProgramType onDemand = onDemandFor(film);

    InstanceDescriptionType instanceDesc = onDemand.getInstanceDescription();
    CaptionLanguageType captionLanguage =
        Iterables.getOnlyElement(instanceDesc.getCaptionLanguage());

    assertTrue(captionLanguage.isClosed());
    assertEquals(captionLanguage.getValue(), "gla");
  }

  @Test
  public void testSubtitledFlag() {
    CaptionLanguageType captionLanguage =
        Iterables.getOnlyElement(
            onDemandFor(createNitroFilm(true)).getInstanceDescription().getCaptionLanguage());

    assertTrue(captionLanguage.isClosed());
    assertEquals("en", captionLanguage.getValue());

    assertTrue(
        onDemandFor(createNitroFilm(false))
            .getInstanceDescription()
            .getCaptionLanguage()
            .isEmpty());
  }

  private ExtendedOnDemandProgramType onDemandFor(Item item) {
    ItemOnDemandHierarchy hierarchy = hierarchyFrom(item);
    String onDemandImi =
        idGenerator.generateOnDemandImi(
            hierarchy.item(), hierarchy.version(), hierarchy.encoding(), hierarchy.location());
    return (ExtendedOnDemandProgramType) generator.generate(hierarchy, onDemandImi);
  }

  @Test
  public void testIfNoActualAvailabilityThenContentNotMarkedAsAvailable() {
    ItemOnDemandHierarchy onDemandHierarchy = hierarchyFrom(createNitroFilm(false));

    onDemandHierarchy.location().getPolicy().setActualAvailabilityStart(null);

    ExtendedOnDemandProgramType onDemand =
        (ExtendedOnDemandProgramType) generator.generate(onDemandHierarchy, ON_DEMAND_IMI);

    InstanceDescriptionType instanceDesc = onDemand.getInstanceDescription();
    Set<String> hrefs =
        ImmutableSet.copyOf(Iterables.transform(instanceDesc.getGenre(), GENRE_TO_HREF));

    assertTrue(
        "No 'media available' genre should be added if no actual availability has been identified",
        hrefs.isEmpty());

    assertEquals("2012-07-03T00:00:00Z", onDemand.getStartOfAvailability().toString());
    assertEquals("2013-07-17T00:00:00Z", onDemand.getEndOfAvailability().toString());
  }

  @Test
  public void testIfActualAvailabilityPresentThenContentMarkedAsAvailable() {
    ItemOnDemandHierarchy onDemandHierarchy = hierarchyFrom(createNitroFilm(false));

    ExtendedOnDemandProgramType onDemand =
        (ExtendedOnDemandProgramType) generator.generate(onDemandHierarchy, ON_DEMAND_IMI);

    InstanceDescriptionType instanceDesc = onDemand.getInstanceDescription();
    Set<String> hrefs =
        ImmutableSet.copyOf(Iterables.transform(instanceDesc.getGenre(), GENRE_TO_HREF));
    Set<String> types =
        ImmutableSet.copyOf(Iterables.transform(instanceDesc.getGenre(), GENRE_TO_TYPE));

    assertEquals(
        "http://refdata.youview.com/mpeg7cs/YouViewMediaAvailabilityCS/2010-09-29#media_available",
        getOnlyElement(hrefs));
    assertEquals("other", getOnlyElement(types));

    assertEquals("2012-07-03T00:00:00Z", onDemand.getStartOfAvailability().toString());
    assertEquals("2013-07-17T00:00:00Z", onDemand.getEndOfAvailability().toString());
  }

  private ItemOnDemandHierarchy hierarchyFrom(Item item) {
    Version version = Iterables.getOnlyElement(item.getVersions());
    Encoding encoding = Iterables.getOnlyElement(version.getManifestedAs());
    Location location = Iterables.getOnlyElement(encoding.getAvailableAt());
    return new ItemOnDemandHierarchy(item, version, encoding, location);
  }

  private Film createNitroFilm(boolean subtitled) {
    Film film = new Film();

    film.setCanonicalUri("http://nitro.bbc.co.uk/programmes/b020tm1g");
    film.setPublisher(Publisher.BBC_NITRO);
    film.setCountriesOfOrigin(ImmutableSet.of(Countries.GB));
    film.setYear(1963);
    film.addVersion(createVersion(subtitled));

    return film;
  }

  private Film createAlbaNitroFilm() {
    Film film = createNitroFilm(true);
    film.setPresentationChannel("http://ref.atlasapi.org/channels/bbcalba");

    return film;
  }

  private Version createVersion(boolean subtitled) {
    Version version = new Version();

    Restriction restriction = new Restriction();
    restriction.setRestricted(true);

    version.setManifestedAs(Sets.newHashSet(createEncoding(subtitled)));

    version.setDuration(Duration.standardMinutes(90));
    version.setCanonicalUri("http://nitro.bbc.co.uk/programmes/b00gszl0");
    version.setRestriction(restriction);

    return version;
  }

  private Encoding createEncoding(boolean subtitled) {
    Encoding encoding = new Encoding();
    encoding.setVideoHorizontalSize(1280);
    encoding.setVideoVerticalSize(720);
    encoding.setVideoAspectRatio("16:9");
    encoding.setVideoBitRate(VIDEO_BITRATE);
    encoding.setAudioDescribed(true);
    encoding.setSigned(true);
    encoding.setSubtitled(subtitled);
    encoding.addAvailableAt(createLocation());

    return encoding;
  }

  private Location createLocation() {
    Location location = new Location();

    Policy policy = new Policy();

    policy.setActualAvailabilityStart(new DateTime(2012, 7, 3, 0, 10, 0, DateTimeZone.UTC));
    policy.setAvailabilityStart(new DateTime(2012, 7, 3, 0, 0, 0, DateTimeZone.UTC));
    policy.setAvailabilityEnd(new DateTime(2013, 7, 17, 0, 0, 0, DateTimeZone.UTC));

    location.setPolicy(policy);

    return location;
  }
}
Пример #23
0
/**
 * Class to monitor config files on local disk. Typical usage is to use the default instance and
 * have it monitor as many config files as needed.
 *
 * <p>The class allows users to specify a watch on a file path and pass in a callback that will be
 * invoked whenever an update to the file is detected. Update detection currently works by periodic
 * polling; if the last modified time on the file is updated and the content hash has changed, all
 * watchers on that file are notified. Note that last modified time is just used as a hint to
 * determine whether to check the content and not for versioning.
 *
 * <p>Objects of this class are thread safe.
 */
public class ConfigFileWatcher {

  private static final Logger LOG = LoggerFactory.getLogger(ConfigFileWatcher.class);
  private static final HashFunction HASH_FUNCTION = Hashing.md5();
  public static final int DEFAULT_POLL_PERIOD_SECONDS = 10;
  private static volatile ConfigFileWatcher DEFAULT_INSTANCE = null;

  // Thread safety note: only addWatch() can add new entries to this map, and that method
  // is synchronized. The reason for using a concurrent map is only to allow the watcher
  // thread to concurrently iterate over it.
  private final ConcurrentMap<String, ConfigFileInfo> watchedFileMap = Maps.newConcurrentMap();
  private final WatcherTask watcherTask;

  /** Creates the default ConfigFileWatcher instance on demand. */
  public static ConfigFileWatcher defaultInstance() {
    if (DEFAULT_INSTANCE == null) {
      synchronized (ConfigFileWatcher.class) {
        if (DEFAULT_INSTANCE == null) {
          DEFAULT_INSTANCE = new ConfigFileWatcher(DEFAULT_POLL_PERIOD_SECONDS);
        }
      }
    }

    return DEFAULT_INSTANCE;
  }

  @VisibleForTesting
  ConfigFileWatcher(int pollPeriodSeconds) {
    ScheduledExecutorService service =
        Executors.newSingleThreadScheduledExecutor(
            new ThreadFactoryBuilder()
                .setDaemon(true)
                .setNameFormat("ConfigFileWatcher-%d")
                .build());
    this.watcherTask = new WatcherTask();
    service.scheduleWithFixedDelay(
        watcherTask, pollPeriodSeconds, pollPeriodSeconds, TimeUnit.SECONDS);
  }

  /**
   * Adds a watch on the specified file. The file must exist, otherwise a FileNotFoundException is
   * returned. If the file is deleted after a watch is established, the watcher will log errors but
   * continue to monitor it, and resume watching if it is recreated.
   *
   * @param filePath path to the file to watch.
   * @param onUpdate function to call when a change is detected to the file. The entire contents of
   *     the file will be passed in to the function. Note that onUpdate will be called once before
   *     this call completes, which facilities initial load of data. This callback is executed
   *     synchronously on the watcher thread - it is important that the function be non-blocking.
   */
  public synchronized void addWatch(String filePath, Function<byte[], Void> onUpdate)
      throws IOException {
    MorePreconditions.checkNotBlank(filePath);
    Preconditions.checkNotNull(onUpdate);

    // Read the file and make the initial onUpdate call.
    File file = new File(filePath);
    ByteSource byteSource = Files.asByteSource(file);
    onUpdate.apply(byteSource.read());

    // Add the file to our map if it isn't already there, and register the new change watcher.
    ConfigFileInfo configFileInfo = watchedFileMap.get(filePath);
    if (configFileInfo == null) {
      configFileInfo = new ConfigFileInfo(file.lastModified(), byteSource.hash(HASH_FUNCTION));
      watchedFileMap.put(filePath, configFileInfo);
    }
    configFileInfo.changeWatchers.add(onUpdate);
  }

  @VisibleForTesting
  public void runWatcherTaskNow() {
    watcherTask.run();
  }

  /**
   * Scheduled task that periodically checks each watched file for updates, and if found to have
   * been changed, triggers notifications on all its watchers.
   *
   * <p>Thread safety note: this task must be run in a single threaded executor; i.e. only one run
   * of the task can be active at any time.
   */
  private class WatcherTask implements Runnable {

    @Override
    public void run() {
      for (Map.Entry<String, ConfigFileInfo> entry : watchedFileMap.entrySet()) {
        String filePath = entry.getKey();
        ConfigFileInfo configFileInfo = entry.getValue();
        try {
          File file = new File(filePath);
          long lastModified = file.lastModified();
          Preconditions.checkArgument(lastModified > 0L);
          if (lastModified != configFileInfo.lastModifiedTimestampMillis) {
            configFileInfo.lastModifiedTimestampMillis = lastModified;
            ByteSource byteSource = Files.asByteSource(file);
            HashCode newContentHash = byteSource.hash(HASH_FUNCTION);
            if (!newContentHash.equals(configFileInfo.contentHash)) {
              configFileInfo.contentHash = newContentHash;
              LOG.info("File {} was modified at {}, notifying watchers.", filePath, lastModified);
              byte[] newContents = byteSource.read();
              for (Function<byte[], Void> watchers : configFileInfo.changeWatchers) {
                try {
                  watchers.apply(newContents);
                } catch (Exception e) {
                  LOG.error(
                      "Exception in watcher callback for {}, ignoring. New file contents were: {}",
                      filePath,
                      new String(newContents, Charsets.UTF_8),
                      e);
                }
              }
            } else {
              LOG.info(
                  "File {} was modified at {} but content hash is unchanged.",
                  filePath,
                  lastModified);
            }
          } else {
            LOG.debug("File {} not modified since {}", filePath, lastModified);
          }
        } catch (Exception e) {
          // We catch and log exceptions related to the update of any specific file, but
          // move on so others aren't affected. Issues can happen for example if the watcher
          // races with an external file replace operation; in that case, the next run should
          // pick up the update.
          // TODO: Consider adding a metric to track this so we can alert on failures.
          LOG.error("Config update check failed for {}", filePath, e);
        }
      }
    }
  }

  /**
   * Encapsulates state related to each watched config file.
   *
   * <p>Thread safety note: 1. changeWatchers is thread safe since it uses a copy-on-write array
   * list. 2. lastModifiedTimestampMillis and contentHash aren't safe to update across threads. We
   * initialize in addWatch() at construction time, and thereafter only the watcher task thread
   * accesses this state, so we are good.
   */
  private static class ConfigFileInfo {

    private final List<Function<byte[], Void>> changeWatchers = Lists.newCopyOnWriteArrayList();
    private long lastModifiedTimestampMillis;
    private HashCode contentHash;

    public ConfigFileInfo(long lastModifiedTimestampMillis, HashCode contentHash) {
      this.lastModifiedTimestampMillis = lastModifiedTimestampMillis;
      Preconditions.checkArgument(lastModifiedTimestampMillis > 0L);
      this.contentHash = Preconditions.checkNotNull(contentHash);
    }
  }
}
 /**
  * Get the MD5 hash of the given stream.
  *
  * @param fis the input stream to use
  * @return a byte array of the MD5 hash
  * @throws java.security.NoSuchAlgorithmException if MD5 is not available
  * @throws IOException if an I/O error occurs
  */
 private static byte[] md5(InputStream fis) throws NoSuchAlgorithmException, IOException {
   return ByteStreams.hash(
           ByteStreams.newInputStreamSupplier(ByteStreams.toByteArray(fis)), Hashing.md5())
       .asBytes();
 }
 /**
  * Get the MD5 hash of the given file.
  *
  * @param file file to compute a hash on
  * @return a byte array of the MD5 hash
  * @throws IOException if file cannot be found
  * @throws NoSuchAlgorithmException if MD5 is not available
  */
 private static byte[] md5(File file) throws NoSuchAlgorithmException, IOException {
   return Files.hash(file, Hashing.md5()).asBytes();
 }
Пример #26
0
 private static String getUniqueUserFilePrefix(String s) {
   return String.valueOf(Hashing.md5().hashUnencodedChars(s).toString()).concat("_");
 }
Пример #27
0
 public static String getMd5(String value) {
   return Hashing.md5().newHasher().putString(value, Charsets.UTF_8).hash().toString();
 }
 public void testToString() {
   assertEquals("Hashing.md5()", Hashing.md5().toString());
   assertEquals("Hashing.sha1()", Hashing.sha1().toString());
   assertEquals("Hashing.sha256()", Hashing.sha256().toString());
   assertEquals("Hashing.sha512()", Hashing.sha512().toString());
 }
/**
 * Tests for the MessageDigestHashFunction.
 *
 * @author Kurt Alfred Kluever
 */
public class MessageDigestHashFunctionTest extends TestCase {
  private static final ImmutableSet<String> INPUTS = ImmutableSet.of("", "Z", "foobar");

  // From "How Provider Implementations Are Requested and Supplied" from
  // http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html
  //  - Some providers may choose to also include alias names.
  //  - For example, the "SHA-1" algorithm might be referred to as "SHA1".
  //  - The algorithm name is not case-sensitive.
  private static final ImmutableMap<String, HashFunction> ALGORITHMS =
      new ImmutableMap.Builder<String, HashFunction>()
          .put("MD5", Hashing.md5())
          .put("SHA", Hashing.sha1()) // Not the official name, but still works
          .put("SHA1", Hashing.sha1()) // Not the official name, but still works
          .put("sHa-1", Hashing.sha1()) // Not the official name, but still works
          .put("SHA-1", Hashing.sha1())
          .put("SHA-256", Hashing.sha256())
          .put("SHA-512", Hashing.sha512())
          .build();

  public void testHashing() {
    for (String stringToTest : INPUTS) {
      for (String algorithmToTest : ALGORITHMS.keySet()) {
        assertMessageDigestHashing(HashTestUtils.ascii(stringToTest), algorithmToTest);
      }
    }
  }

  public void testPutAfterHash() {
    Hasher sha1 = Hashing.sha1().newHasher();

    assertEquals(
        "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
        sha1.putString("The quick brown fox jumps over the lazy dog", Charsets.UTF_8)
            .hash()
            .toString());
    try {
      sha1.putInt(42);
      fail();
    } catch (IllegalStateException expected) {
    }
  }

  public void testHashTwice() {
    Hasher sha1 = Hashing.sha1().newHasher();

    assertEquals(
        "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
        sha1.putString("The quick brown fox jumps over the lazy dog", Charsets.UTF_8)
            .hash()
            .toString());
    try {
      sha1.hash();
      fail();
    } catch (IllegalStateException expected) {
    }
  }

  public void testToString() {
    assertEquals("Hashing.md5()", Hashing.md5().toString());
    assertEquals("Hashing.sha1()", Hashing.sha1().toString());
    assertEquals("Hashing.sha256()", Hashing.sha256().toString());
    assertEquals("Hashing.sha512()", Hashing.sha512().toString());
  }

  private static void assertMessageDigestHashing(byte[] input, String algorithmName) {
    try {
      MessageDigest digest = MessageDigest.getInstance(algorithmName);
      assertEquals(
          HashCode.fromBytes(digest.digest(input)), ALGORITHMS.get(algorithmName).hashBytes(input));
      for (int bytes = 4; bytes <= digest.getDigestLength(); bytes++) {
        assertEquals(
            HashCode.fromBytes(Arrays.copyOf(digest.digest(input), bytes)),
            new MessageDigestHashFunction(algorithmName, bytes, algorithmName).hashBytes(input));
      }
      try {
        int maxSize = digest.getDigestLength();
        new MessageDigestHashFunction(algorithmName, maxSize + 1, algorithmName);
        fail();
      } catch (IllegalArgumentException expected) {
      }
    } catch (NoSuchAlgorithmException nsae) {
      throw new AssertionError(nsae);
    }
  }
}
/**
 * FilesystemStorageStrategyImpl implements a blob store that stores objects on the file system.
 * Content metadata and user attributes are stored in extended attributes if the file system
 * supports them. Directory blobs (blobs that end with a /) cannot have content, but otherwise
 * appear in LIST like normal blobs.
 */
public class FilesystemStorageStrategyImpl implements LocalStorageStrategy {

  private static final String XATTR_CACHE_CONTROL = "user.cache-control";
  private static final String XATTR_CONTENT_DISPOSITION = "user.content-disposition";
  private static final String XATTR_CONTENT_ENCODING = "user.content-encoding";
  private static final String XATTR_CONTENT_LANGUAGE = "user.content-language";
  private static final String XATTR_CONTENT_MD5 = "user.content-md5";
  private static final String XATTR_CONTENT_TYPE = "user.content-type";
  private static final String XATTR_EXPIRES = "user.expires";
  private static final String XATTR_USER_METADATA_PREFIX = "user.user-metadata.";
  private static final byte[] DIRECTORY_MD5 = Hashing.md5().hashBytes(new byte[0]).asBytes();

  private static final String BACK_SLASH = "\\";

  @Resource protected Logger logger = Logger.NULL;

  protected final Provider<BlobBuilder> blobBuilders;
  protected final String baseDirectory;
  protected final boolean autoDetectContentType;
  protected final FilesystemContainerNameValidator filesystemContainerNameValidator;
  protected final FilesystemBlobKeyValidator filesystemBlobKeyValidator;
  private final Supplier<Location> defaultLocation;

  @Inject
  protected FilesystemStorageStrategyImpl(
      Provider<BlobBuilder> blobBuilders,
      @Named(FilesystemConstants.PROPERTY_BASEDIR) String baseDir,
      @Named(FilesystemConstants.PROPERTY_AUTO_DETECT_CONTENT_TYPE) boolean autoDetectContentType,
      FilesystemContainerNameValidator filesystemContainerNameValidator,
      FilesystemBlobKeyValidator filesystemBlobKeyValidator,
      Supplier<Location> defaultLocation) {
    this.blobBuilders = checkNotNull(blobBuilders, "filesystem storage strategy blobBuilders");
    this.baseDirectory = checkNotNull(baseDir, "filesystem storage strategy base directory");
    this.autoDetectContentType = autoDetectContentType;
    this.filesystemContainerNameValidator =
        checkNotNull(filesystemContainerNameValidator, "filesystem container name validator");
    this.filesystemBlobKeyValidator =
        checkNotNull(filesystemBlobKeyValidator, "filesystem blob key validator");
    this.defaultLocation = defaultLocation;
  }

  @Override
  public boolean containerExists(String container) {
    filesystemContainerNameValidator.validate(container);
    return directoryExists(container, null);
  }

  @Override
  public Collection<String> getAllContainerNames() {
    File[] files = new File(buildPathStartingFromBaseDir()).listFiles();
    if (files == null) {
      return ImmutableList.of();
    }
    ImmutableList.Builder<String> containers = ImmutableList.builder();
    for (File file : files) {
      if (file.isDirectory()) {
        containers.add(file.getName());
      }
    }
    return containers.build();
  }

  @Override
  public boolean createContainerInLocation(
      String container, Location location, CreateContainerOptions options) {
    // TODO: implement location
    logger.debug("Creating container %s", container);
    filesystemContainerNameValidator.validate(container);
    boolean created = createDirectoryWithResult(container, null);
    if (created) {
      setContainerAccess(
          container,
          options.isPublicRead() ? ContainerAccess.PUBLIC_READ : ContainerAccess.PRIVATE);
    }
    return created;
  }

  @Override
  public ContainerAccess getContainerAccess(String container) {
    Path path = new File(buildPathStartingFromBaseDir(container)).toPath();

    if (isWindows()) {
      try {
        if (isPrivate(path)) {
          return ContainerAccess.PRIVATE;
        } else {
          return ContainerAccess.PUBLIC_READ;
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } else {
      Set<PosixFilePermission> permissions;
      try {
        permissions = getPosixFilePermissions(path);
      } catch (IOException ioe) {
        throw Throwables.propagate(ioe);
      }
      return permissions.contains(PosixFilePermission.OTHERS_READ)
          ? ContainerAccess.PUBLIC_READ
          : ContainerAccess.PRIVATE;
    }
  }

  @Override
  public void setContainerAccess(String container, ContainerAccess access) {
    Path path = new File(buildPathStartingFromBaseDir(container)).toPath();

    if (isWindows()) {
      try {
        if (access == ContainerAccess.PRIVATE) {
          setPrivate(path);
        } else {
          setPublic(path);
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } else {
      Set<PosixFilePermission> permissions;
      try {
        permissions = getPosixFilePermissions(path);
        if (access == ContainerAccess.PRIVATE) {
          permissions.remove(PosixFilePermission.OTHERS_READ);
        } else if (access == ContainerAccess.PUBLIC_READ) {
          permissions.add(PosixFilePermission.OTHERS_READ);
        }
        setPosixFilePermissions(path, permissions);
      } catch (IOException ioe) {
        throw Throwables.propagate(ioe);
      }
    }
  }

  @Override
  public void deleteContainer(String container) {
    filesystemContainerNameValidator.validate(container);
    if (!containerExists(container)) {
      return;
    }
    deleteDirectory(container, null);
  }

  @Override
  public void clearContainer(final String container) {
    clearContainer(container, ListContainerOptions.Builder.recursive());
  }

  @Override
  public void clearContainer(String container, ListContainerOptions options) {
    filesystemContainerNameValidator.validate(container);
    if (options.getDir() != null) {
      container += denormalize("/" + options.getDir());
    }
    try {
      File containerFile = openFolder(container);
      File[] children = containerFile.listFiles();
      if (null != children) {
        for (File child : children)
          if (options.isRecursive() || child.isFile()) {
            Utils.deleteRecursively(child);
          }
      }
    } catch (IOException e) {
      logger.error(e, "An error occurred while clearing container %s", container);
      Throwables.propagate(e);
    }
  }

  @Override
  public StorageMetadata getContainerMetadata(String container) {
    MutableStorageMetadata metadata = new MutableStorageMetadataImpl();
    metadata.setName(container);
    metadata.setType(StorageType.CONTAINER);
    metadata.setLocation(getLocation(container));
    Path path = new File(buildPathStartingFromBaseDir(container)).toPath();
    BasicFileAttributes attr;
    try {
      attr = readAttributes(path, BasicFileAttributes.class);
    } catch (IOException e) {
      throw Throwables.propagate(e);
    }
    metadata.setCreationDate(new Date(attr.creationTime().toMillis()));
    return metadata;
  }

  @Override
  public boolean blobExists(String container, String key) {
    filesystemContainerNameValidator.validate(container);
    filesystemBlobKeyValidator.validate(key);
    try {
      return buildPathAndChecksIfBlobExists(container, key);
    } catch (IOException e) {
      logger.error(e, "An error occurred while checking key %s in container %s", container, key);
      throw Throwables.propagate(e);
    }
  }

  /**
   * Returns all the blobs key inside a container
   *
   * @param container
   * @return
   * @throws IOException
   */
  @Override
  public Iterable<String> getBlobKeysInsideContainer(String container) throws IOException {
    filesystemContainerNameValidator.validate(container);
    // check if container exists
    // TODO maybe an error is more appropriate
    Set<String> blobNames = Sets.newHashSet();
    if (!containerExists(container)) {
      return blobNames;
    }

    File containerFile = openFolder(container);
    final int containerPathLength = containerFile.getAbsolutePath().length() + 1;
    populateBlobKeysInContainer(
        containerFile,
        blobNames,
        new Function<String, String>() {
          @Override
          public String apply(String string) {
            return string.substring(containerPathLength);
          }
        });
    return blobNames;
  }

  @Override
  public Blob getBlob(final String container, final String key) {
    BlobBuilder builder = blobBuilders.get();
    builder.name(key);
    File file = getFileForBlobKey(container, key);
    ByteSource byteSource;

    if (getDirectoryBlobSuffix(key) != null) {
      logger.debug("%s - %s is a directory", container, key);
      byteSource = ByteSource.empty();
    } else {
      byteSource = Files.asByteSource(file);
    }
    try {
      String cacheControl = null;
      String contentDisposition = null;
      String contentEncoding = null;
      String contentLanguage = null;
      String contentType = null;
      HashCode hashCode = null;
      Date expires = null;
      ImmutableMap.Builder<String, String> userMetadata = ImmutableMap.builder();

      UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(file.toPath());
      if (view != null) {
        Set<String> attributes = ImmutableSet.copyOf(view.list());

        cacheControl = readStringAttributeIfPresent(view, attributes, XATTR_CACHE_CONTROL);
        contentDisposition =
            readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_DISPOSITION);
        contentEncoding = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_ENCODING);
        contentLanguage = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_LANGUAGE);
        contentType = readStringAttributeIfPresent(view, attributes, XATTR_CONTENT_TYPE);
        if (contentType == null && autoDetectContentType) {
          contentType = probeContentType(file.toPath());
        }
        if (attributes.contains(XATTR_CONTENT_MD5)) {
          ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_CONTENT_MD5));
          view.read(XATTR_CONTENT_MD5, buf);
          hashCode = HashCode.fromBytes(buf.array());
        }
        if (attributes.contains(XATTR_EXPIRES)) {
          ByteBuffer buf = ByteBuffer.allocate(view.size(XATTR_EXPIRES));
          view.read(XATTR_EXPIRES, buf);
          buf.flip();
          expires = new Date(buf.asLongBuffer().get());
        }
        for (String attribute : attributes) {
          if (!attribute.startsWith(XATTR_USER_METADATA_PREFIX)) {
            continue;
          }
          String value = readStringAttributeIfPresent(view, attributes, attribute);
          userMetadata.put(attribute.substring(XATTR_USER_METADATA_PREFIX.length()), value);
        }

        builder
            .payload(byteSource)
            .cacheControl(cacheControl)
            .contentDisposition(contentDisposition)
            .contentEncoding(contentEncoding)
            .contentLanguage(contentLanguage)
            .contentLength(byteSource.size())
            .contentMD5(hashCode)
            .contentType(contentType)
            .expires(expires)
            .userMetadata(userMetadata.build());
      } else {
        builder
            .payload(byteSource)
            .contentLength(byteSource.size())
            .contentMD5(byteSource.hash(Hashing.md5()).asBytes());
      }
    } catch (IOException e) {
      throw Throwables.propagate(e);
    }
    Blob blob = builder.build();
    blob.getMetadata().setContainer(container);
    blob.getMetadata().setLastModified(new Date(file.lastModified()));
    blob.getMetadata().setSize(file.length());
    if (blob.getPayload().getContentMetadata().getContentMD5() != null)
      blob.getMetadata()
          .setETag(
              base16().lowerCase().encode(blob.getPayload().getContentMetadata().getContentMD5()));
    return blob;
  }

  private void writeCommonMetadataAttr(UserDefinedFileAttributeView view, Blob blob)
      throws IOException {
    ContentMetadata metadata = blob.getMetadata().getContentMetadata();
    writeStringAttributeIfPresent(view, XATTR_CACHE_CONTROL, metadata.getCacheControl());
    writeStringAttributeIfPresent(
        view, XATTR_CONTENT_DISPOSITION, metadata.getContentDisposition());
    writeStringAttributeIfPresent(view, XATTR_CONTENT_ENCODING, metadata.getContentEncoding());
    writeStringAttributeIfPresent(view, XATTR_CONTENT_LANGUAGE, metadata.getContentLanguage());
    writeStringAttributeIfPresent(view, XATTR_CONTENT_TYPE, metadata.getContentType());
    Date expires = metadata.getExpires();
    if (expires != null) {
      ByteBuffer buf = ByteBuffer.allocate(Longs.BYTES).putLong(expires.getTime());
      buf.flip();
      view.write(XATTR_EXPIRES, buf);
    }
    for (Map.Entry<String, String> entry : blob.getMetadata().getUserMetadata().entrySet()) {
      writeStringAttributeIfPresent(
          view, XATTR_USER_METADATA_PREFIX + entry.getKey(), entry.getValue());
    }
  }

  private String putDirectoryBlob(final String containerName, final Blob blob) throws IOException {
    String blobKey = blob.getMetadata().getName();
    ContentMetadata metadata = blob.getMetadata().getContentMetadata();
    Long contentLength = metadata.getContentLength();
    if (contentLength != null && contentLength != 0) {
      throw new IllegalArgumentException("Directory blob cannot have content: " + blobKey);
    }
    File outputFile = getFileForBlobKey(containerName, blobKey);
    Path outputPath = outputFile.toPath();
    if (!outputFile.isDirectory() && !outputFile.mkdirs()) {
      throw new IOException("Unable to mkdir: " + outputPath);
    }

    UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(outputPath);
    if (view != null) {
      try {
        view.write(XATTR_CONTENT_MD5, ByteBuffer.wrap(DIRECTORY_MD5));
        writeCommonMetadataAttr(view, blob);
      } catch (IOException e) {
        logger.debug("xattrs not supported on %s", outputPath);
      }
    } else {
      logger.warn("xattr not supported on %s", blobKey);
    }

    return base16().lowerCase().encode(DIRECTORY_MD5);
  }

  @Override
  public String putBlob(final String containerName, final Blob blob) throws IOException {
    String blobKey = blob.getMetadata().getName();
    Payload payload = blob.getPayload();
    filesystemContainerNameValidator.validate(containerName);
    filesystemBlobKeyValidator.validate(blobKey);
    if (getDirectoryBlobSuffix(blobKey) != null) {
      return putDirectoryBlob(containerName, blob);
    }
    File outputFile = getFileForBlobKey(containerName, blobKey);
    // TODO: should we use a known suffix to filter these out during list?
    String tmpBlobName = blobKey + "-" + UUID.randomUUID();
    File tmpFile = getFileForBlobKey(containerName, tmpBlobName);
    Path tmpPath = tmpFile.toPath();
    HashingInputStream his = null;
    try {
      Files.createParentDirs(tmpFile);
      his = new HashingInputStream(Hashing.md5(), payload.openStream());
      long actualSize = Files.asByteSink(tmpFile).writeFrom(his);
      Long expectedSize = blob.getMetadata().getContentMetadata().getContentLength();
      if (expectedSize != null && actualSize != expectedSize) {
        throw new IOException(
            "Content-Length mismatch, actual: " + actualSize + " expected: " + expectedSize);
      }
      HashCode actualHashCode = his.hash();
      HashCode expectedHashCode = payload.getContentMetadata().getContentMD5AsHashCode();
      if (expectedHashCode != null && !actualHashCode.equals(expectedHashCode)) {
        throw new IOException(
            "MD5 hash code mismatch, actual: " + actualHashCode + " expected: " + expectedHashCode);
      }
      payload.getContentMetadata().setContentMD5(actualHashCode);

      if (outputFile.exists()) {
        delete(outputFile);
      }

      UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(tmpPath);
      if (view != null) {
        try {
          view.write(XATTR_CONTENT_MD5, ByteBuffer.wrap(actualHashCode.asBytes()));
          writeCommonMetadataAttr(view, blob);
        } catch (IOException e) {
          logger.debug("xattrs not supported on %s", tmpPath);
        }
      }

      setBlobAccess(containerName, tmpBlobName, BlobAccess.PRIVATE);

      if (!tmpFile.renameTo(outputFile)) {
        throw new RuntimeException("Could not rename file " + tmpFile + " to " + outputFile);
      }

      return base16().lowerCase().encode(actualHashCode.asBytes());
    } catch (IOException ex) {
      if (tmpFile != null) {
        try {
          delete(tmpFile);
        } catch (IOException e) {
          logger.debug("Could not delete %s: %s", tmpFile, e);
        }
      }
      throw ex;
    } finally {
      closeQuietly(his);
      if (payload != null) {
        payload.release();
      }
    }
  }

  @Override
  public void removeBlob(final String container, final String blobKey) {
    filesystemContainerNameValidator.validate(container);
    filesystemBlobKeyValidator.validate(blobKey);
    String fileName = buildPathStartingFromBaseDir(container, blobKey);
    logger.debug("Deleting blob %s", fileName);
    File fileToBeDeleted = new File(fileName);

    if (fileToBeDeleted.isDirectory()) {
      try {
        UserDefinedFileAttributeView view =
            getUserDefinedFileAttributeView(fileToBeDeleted.toPath());
        if (view != null) {
          for (String s : view.list()) {
            view.delete(s);
          }
        }
      } catch (IOException e) {
        logger.debug("Could not delete attributes from %s: %s", fileToBeDeleted, e);
      }
    }

    try {
      delete(fileToBeDeleted);
    } catch (IOException e) {
      logger.debug("Could not delete %s: %s", fileToBeDeleted, e);
    }

    // now examine if the key of the blob is a complex key (with a directory structure)
    // and eventually remove empty directory
    removeDirectoriesTreeOfBlobKey(container, blobKey);
  }

  @Override
  public BlobAccess getBlobAccess(String containerName, String blobName) {
    Path path = new File(buildPathStartingFromBaseDir(containerName, blobName)).toPath();

    if (isWindows()) {
      try {
        if (isPrivate(path)) {
          return BlobAccess.PRIVATE;
        } else {
          return BlobAccess.PUBLIC_READ;
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } else {
      Set<PosixFilePermission> permissions;
      try {
        permissions = getPosixFilePermissions(path);
      } catch (IOException ioe) {
        throw Throwables.propagate(ioe);
      }
      return permissions.contains(PosixFilePermission.OTHERS_READ)
          ? BlobAccess.PUBLIC_READ
          : BlobAccess.PRIVATE;
    }
  }

  @Override
  public void setBlobAccess(String container, String name, BlobAccess access) {
    Path path = new File(buildPathStartingFromBaseDir(container, name)).toPath();
    if (isWindows()) {
      try {
        if (access == BlobAccess.PRIVATE) {
          setPrivate(path);
        } else {
          setPublic(path);
        }
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    } else {
      Set<PosixFilePermission> permissions;
      try {
        permissions = getPosixFilePermissions(path);
        if (access == BlobAccess.PRIVATE) {
          permissions.remove(PosixFilePermission.OTHERS_READ);
        } else if (access == BlobAccess.PUBLIC_READ) {
          permissions.add(PosixFilePermission.OTHERS_READ);
        }
        setPosixFilePermissions(path, permissions);
      } catch (IOException ioe) {
        throw Throwables.propagate(ioe);
      }
    }
  }

  @Override
  public Location getLocation(final String containerName) {
    return defaultLocation.get();
  }

  @Override
  public String getSeparator() {
    return File.separator;
  }

  public boolean createContainer(String container) {
    filesystemContainerNameValidator.validate(container);
    return createContainerInLocation(container, null, CreateContainerOptions.NONE);
  }

  public Blob newBlob(@ParamValidators({FilesystemBlobKeyValidator.class}) String name) {
    filesystemBlobKeyValidator.validate(name);
    return blobBuilders.get().name(name).build();
  }

  /**
   * Returns a {@link File} object that links to the blob
   *
   * @param container
   * @param blobKey
   * @return
   */
  public File getFileForBlobKey(String container, String blobKey) {
    filesystemContainerNameValidator.validate(container);
    filesystemBlobKeyValidator.validate(blobKey);
    String fileName = buildPathStartingFromBaseDir(container, blobKey);
    File blobFile = new File(fileName);
    return blobFile;
  }

  public boolean directoryExists(String container, String directory) {
    return buildPathAndChecksIfDirectoryExists(container, directory);
  }

  public void createDirectory(String container, String directory) {
    createDirectoryWithResult(container, directory);
  }

  public void deleteDirectory(String container, String directory) {
    // create complete dir path
    String fullDirPath = buildPathStartingFromBaseDir(container, directory);
    try {
      Utils.deleteRecursively(new File(fullDirPath));
    } catch (IOException ex) {
      logger.error("An error occurred removing directory %s.", fullDirPath);
      Throwables.propagate(ex);
    }
  }

  public long countBlobs(String container, ListContainerOptions options) {
    // TODO: honor options
    try {
      return Iterables.size(getBlobKeysInsideContainer(container));
    } catch (IOException ioe) {
      throw Throwables.propagate(ioe);
    }
  }

  // ---------------------------------------------------------- Private methods

  private boolean buildPathAndChecksIfBlobExists(String... tokens) throws IOException {
    String path = buildPathStartingFromBaseDir(tokens);
    File file = new File(path);
    boolean exists = file.exists() && file.isFile();
    if (!exists
        && getDirectoryBlobSuffix(tokens[tokens.length - 1]) != null
        && file.isDirectory()) {
      UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(file.toPath());
      exists = view != null && view.list().contains(XATTR_CONTENT_MD5);
    }
    return exists;
  }

  private static String getDirectoryBlobSuffix(String key) {
    for (String suffix : BlobStoreConstants.DIRECTORY_SUFFIXES) {
      if (key.endsWith(suffix)) {
        return suffix;
      }
    }
    return null;
  }

  private static String directoryBlobName(String key) {
    String suffix = getDirectoryBlobSuffix(key);
    if (suffix != null) {
      if (!BlobStoreConstants.DIRECTORY_BLOB_SUFFIX.equals(suffix)) {
        key = key.substring(0, key.lastIndexOf(suffix));
      }
      return key + BlobStoreConstants.DIRECTORY_BLOB_SUFFIX;
    }
    return null;
  }

  private UserDefinedFileAttributeView getUserDefinedFileAttributeView(Path path)
      throws IOException {
    return getFileAttributeView(path, UserDefinedFileAttributeView.class);
  }

  /**
   * Check if the file system resource whose name is obtained applying buildPath on the input path
   * tokens is a directory, otherwise a RuntimeException is thrown
   *
   * @param tokens the tokens that make up the name of the resource on the file system
   */
  private boolean buildPathAndChecksIfDirectoryExists(String... tokens) {
    String path = buildPathStartingFromBaseDir(tokens);
    File file = new File(path);
    boolean exists = file.exists() || file.isDirectory();
    return exists;
  }

  /**
   * Facility method used to concatenate path tokens normalizing separators
   *
   * @param pathTokens all the string in the proper order that must be concatenated in order to
   *     obtain the filename
   * @return the resulting string
   */
  protected String buildPathStartingFromBaseDir(String... pathTokens) {
    String normalizedToken = removeFileSeparatorFromBorders(normalize(baseDirectory), true);
    StringBuilder completePath = new StringBuilder(normalizedToken);
    if (pathTokens != null && pathTokens.length > 0) {
      for (int i = 0; i < pathTokens.length; i++) {
        if (pathTokens[i] != null) {
          normalizedToken = removeFileSeparatorFromBorders(normalize(pathTokens[i]), false);
          completePath.append(File.separator).append(normalizedToken);
        }
      }
    }
    return completePath.toString();
  }

  /**
   * Substitutes all the file separator occurrences in the path with a file separator for the
   * current operative system
   *
   * @param pathToBeNormalized
   * @return
   */
  private static String normalize(String pathToBeNormalized) {
    if (null != pathToBeNormalized && pathToBeNormalized.contains(BACK_SLASH)) {
      if (!BACK_SLASH.equals(File.separator)) {
        return pathToBeNormalized.replace(BACK_SLASH, File.separator);
      }
    }
    return pathToBeNormalized;
  }

  private static String denormalize(String pathToDenormalize) {
    if (null != pathToDenormalize && pathToDenormalize.contains("/")) {
      if (BACK_SLASH.equals(File.separator)) {
        return pathToDenormalize.replace("/", BACK_SLASH);
      }
    }
    return pathToDenormalize;
  }

  /**
   * Remove leading and trailing separator character from the string.
   *
   * @param pathToBeCleaned
   * @param onlyTrailing only trailing separator char from path
   * @return
   */
  private String removeFileSeparatorFromBorders(String pathToBeCleaned, boolean onlyTrailing) {
    if (null == pathToBeCleaned || pathToBeCleaned.equals("")) return pathToBeCleaned;

    int beginIndex = 0;
    int endIndex = pathToBeCleaned.length();

    // search for separator chars
    if (!onlyTrailing) {
      if (pathToBeCleaned.substring(0, 1).equals(File.separator)) beginIndex = 1;
    }
    if (pathToBeCleaned.substring(pathToBeCleaned.length() - 1).equals(File.separator)) endIndex--;

    return pathToBeCleaned.substring(beginIndex, endIndex);
  }

  /**
   * Removes recursively the directory structure of a complex blob key, only if the directory is
   * empty
   *
   * @param container
   * @param blobKey
   */
  private void removeDirectoriesTreeOfBlobKey(String container, String blobKey) {
    String normalizedBlobKey = denormalize(blobKey);
    // exists is no path is present in the blobkey
    if (!normalizedBlobKey.contains(File.separator)) return;

    File file = new File(normalizedBlobKey);
    // TODO
    // "/media/data/works/java/amazon/jclouds/master/filesystem/aa/bb/cc/dd/eef6f0c8-0206-460b-8870-352e6019893c.txt"
    String parentPath = file.getParent();
    // no need to manage "/" parentPath, because "/" cannot be used as start
    // char of blobkey
    if (!isNullOrEmpty(parentPath)) {
      // remove parent directory only it's empty
      File directory = new File(buildPathStartingFromBaseDir(container, parentPath));
      // don't delete directory if it's a directory blob
      try {
        UserDefinedFileAttributeView view = getUserDefinedFileAttributeView(directory.toPath());
        if (view == null) { // OSX HFS+ does not support UserDefinedFileAttributeView
          logger.debug("Could not look for attributes from %s", directory);
        } else if (!view.list().isEmpty()) {
          return;
        }
      } catch (IOException e) {
        logger.debug("Could not look for attributes from %s: %s", directory, e);
      }

      String[] children = directory.list();
      if (null == children || children.length == 0) {
        try {
          delete(directory);
        } catch (IOException e) {
          logger.debug("Could not delete %s: %s", directory, e);
          return;
        }
        // recursively call for removing other path
        removeDirectoriesTreeOfBlobKey(container, parentPath);
      }
    }
  }

  private File openFolder(String folderName) throws IOException {
    String baseFolderName = buildPathStartingFromBaseDir(folderName);
    File folder = new File(baseFolderName);
    if (folder.exists()) {
      if (!folder.isDirectory()) {
        throw new IOException("Resource " + baseFolderName + " isn't a folder.");
      }
    }
    return folder;
  }

  private static void populateBlobKeysInContainer(
      File directory, Set<String> blobNames, Function<String, String> function) {
    File[] children = directory.listFiles();
    if (children == null) {
      return;
    }
    for (File child : children) {
      if (child.isFile()) {
        blobNames.add(function.apply(child.getAbsolutePath()));
      } else if (child.isDirectory()) {
        blobNames.add(
            function.apply(child.getAbsolutePath()) + File.separator); // TODO: undo if failures
        populateBlobKeysInContainer(child, blobNames, function);
      }
    }
  }

  /**
   * Creates a directory and returns the result
   *
   * @param container
   * @param directory
   * @return true if the directory was created, otherwise false
   */
  protected boolean createDirectoryWithResult(String container, String directory) {
    String directoryFullName = buildPathStartingFromBaseDir(container, directory);
    logger.debug("Creating directory %s", directoryFullName);

    // cannot use directoryFullName, because the following method rebuild
    // another time the path starting from base directory
    if (buildPathAndChecksIfDirectoryExists(container, directory)) {
      logger.debug("Directory %s already exists", directoryFullName);
      return false;
    }

    File directoryToCreate = new File(directoryFullName);
    boolean result = directoryToCreate.mkdirs();
    return result;
  }

  /** Read the String representation of filesystem attribute, or return null if not present. */
  private static String readStringAttributeIfPresent(
      UserDefinedFileAttributeView view, Set<String> attributes, String name) throws IOException {
    if (!attributes.contains(name)) {
      return null;
    }
    ByteBuffer buf = ByteBuffer.allocate(view.size(name));
    view.read(name, buf);
    return new String(buf.array(), StandardCharsets.UTF_8);
  }

  /** Write an filesystem attribute, if its value is non-null. */
  private static void writeStringAttributeIfPresent(
      UserDefinedFileAttributeView view, String name, String value) throws IOException {
    if (value != null) {
      view.write(name, ByteBuffer.wrap(value.getBytes(StandardCharsets.UTF_8)));
    }
  }

  private static void copyStringAttributeIfPresent(
      UserDefinedFileAttributeView view, String name, Map<String, String> attrs)
      throws IOException {
    writeStringAttributeIfPresent(view, name, attrs.get(name));
  }
}