All Downloads are FREE. Search and download functionalities are using the official Maven repository.

eu.ciechanowiec.sling.rocket.jcr.NodeProperties Maven / Gradle / Ivy

There is a newer version: 13.32.0
Show newest version
package eu.ciechanowiec.sling.rocket.jcr;

import eu.ciechanowiec.conditional.Conditional;
import eu.ciechanowiec.sling.rocket.commons.ResourceAccess;
import eu.ciechanowiec.sling.rocket.jcr.path.JCRPath;
import eu.ciechanowiec.sling.rocket.jcr.path.WithJCRPath;
import eu.ciechanowiec.sling.rocket.unit.DataSize;
import eu.ciechanowiec.sling.rocket.unit.DataUnit;
import eu.ciechanowiec.sneakyfun.SneakyConsumer;
import lombok.SneakyThrows;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;

import javax.jcr.*;
import javax.jcr.nodetype.NodeType;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

import static eu.ciechanowiec.sneakyfun.SneakyFunction.sneaky;

/**
 * 

* Represents {@link Property}-ies of a {@link Node}. *

*

* The class provides API operations on {@link Property}-ies * in a way detached from an ongoing {@link Session}. {@link Session}'s live cycle is supposed to be fully * managed by {@link NodeProperties} itself in an encapsulated manner. *

*/ @SuppressWarnings({ "WeakerAccess", "ClassWithTooManyMethods", "MethodCount", "MultipleStringLiterals", "PMD.AvoidDuplicateLiterals", "PMD.CouplingBetweenObjects", "PMD.ExcessivePublicCount" }) @Slf4j @ToString public class NodeProperties implements WithJCRPath { private final JCRPath jcrPath; @ToString.Exclude private final ResourceAccess resourceAccess; /** * Constructs an instance of this class. * @param jcrNodePath {@link JCRPath} to the underlying {@link Node} * @param resourceAccess {@link ResourceAccess} that will be used by the constructed * object to acquire access to resources */ public NodeProperties(JCRPath jcrNodePath, ResourceAccess resourceAccess) { this.jcrPath = jcrNodePath; this.resourceAccess = resourceAccess; log.trace("Initialized {}", this); } /** * Constructs an instance of this class. * @param withJCRPath object that contains a {@link JCRPath} to the underlying {@link Node} * @param resourceAccess {@link ResourceAccess} that will be used by the constructed * object to acquire access to resources */ public NodeProperties(WithJCRPath withJCRPath, ResourceAccess resourceAccess) { this(withJCRPath.jcrPath(), resourceAccess); } /** * Retrieves the primary type of the underlying {@link Node}. * @return primary type of the underlying {@link Node} */ public String primaryType() { log.trace("Retrieving the primary type of {}", this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(sneaky(node -> Optional.ofNullable(node.getPrimaryNodeType()))) .map(NodeType::getName) .orElseThrow(); } } /** * Checks if the underlying {@link Node} is of one of the specified primary types. * @param acceptablePrimaryTypes names of the primary types against which the check is performed * @return {@code true} if the underlying {@link Node} is of one of the specified primary types; * {@code false} otherwise */ public boolean isPrimaryType(String... acceptablePrimaryTypes) { return isPrimaryType(List.of(acceptablePrimaryTypes)); } /** * Checks if the underlying {@link Node} is of one of the specified primary types. * @param acceptablePrimaryTypes names of the primary types against which the check is performed * @return {@code true} if the underlying {@link Node} is of one of the specified primary types; * {@code false} otherwise */ public boolean isPrimaryType(Collection acceptablePrimaryTypes) { log.trace("Checking if {} is of this primary type: '{}'", this, acceptablePrimaryTypes); String actualPrimaryType = primaryType(); return acceptablePrimaryTypes.stream().anyMatch(actualPrimaryType::equals); } /** * Asserts that the underlying {@link Node} is of the specified primary type. * @param expectedPrimaryType name of the primary type against which the assertion is performed * @throws IllegalPrimaryTypeException if the underlying {@link Node} isn't of the specified primary type */ public void assertPrimaryType(String expectedPrimaryType) { log.trace("Asserting that {} is of '{}' primary type", this, expectedPrimaryType); Conditional.isTrueOrThrow( isPrimaryType(expectedPrimaryType), new IllegalPrimaryTypeException(expectedPrimaryType) ); } /** *

* Retrieves the {@link Value} of the specified {@link Property} and converts it into the given type. *

*
    *
  1. * It is guaranteed that the method supports types specified in the {@link Class} fields of * {@link DefaultProperties}. Other types and translations between types are supported to the extent that they * are supported by the underlying {@link ValueMap#get(String, Object)} method. *
  2. *
  3. * To ensure that the supported type is passed, it is recommended to use factory {@code of} methods from * {@link DefaultProperties} when specifying the default value, e.g.: *
    {@code
         *    double price = nodeProperties.propertyValue("price", DefaultProperties.of(99.99));
         *    }
    *
  4. *
  5. *

    * Both unary and multi-valued {@link Property}-ies are supported. *

    * Usage example with a unary {@link Property}: *
    {@code
         *    long price = nodeProperties.propertyValue("price", DefaultProperties.LONG_ZERO);
         *    String name = nodeProperties.propertyValue("name", DefaultProperties.STRING_EMPTY);
         *    }
    * Usage example with a multi-valued {@link Property}: *
    {@code
         *    long[] prices = nodeProperties.propertyValue("prices", new long[]{DefaultProperties.LONG_ZERO});
         *    String[] names = nodeProperties.propertyValue("names", new String[]{DefaultProperties.STRING_EMPTY});
         *    }
    *
  6. *
* @param propertyName name of the {@link Property} from which the {@link Value} should be retrieved * @param defaultValue default {@link Value} to use if the specified {@link Property} does not exist or * its value cannot be converted to the requested type; the {@code defaultValue} is also used * to define the type to convert the {@link Value} to * @return {@link Value} of the specified {@link Property} converted to the requested type or the * {@code defaultValue} if the specified {@link Property} does not exist or its {@link Value} cannot be * converted to the requested type * @param expected type */ public T propertyValue(String propertyName, T defaultValue) { log.trace("Getting '{}' property value for {}", propertyName, this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .map(Resource::getValueMap) .map(WithPrimitiveArrayTranslation::new) .map(valueMapWithTranslation -> valueMapWithTranslation.get(propertyName, defaultValue)) .orElse(defaultValue); } } /** *

* Retrieves the {@link Value} of the specified {@link Property} and converts it into the given type. *

*
    *
  1. * It is guaranteed that the method supports types specified in the {@link Class} fields of * {@link DefaultProperties}. Other types and translations between types are supported to the extent that they * are supported by the underlying {@link ValueMap#get(String, Class)} method. *
  2. *
  3. * To ensure that the supported type is passed, it is recommended to use {@link Class} fields of * {@link DefaultProperties} when specifying the default value, e.g.: *
    {@code
         *    Optional price = nodeProperties.propertyValue("price", DefaultProperties.DOUBLE_CLASS);
         *    }
    *
  4. *
  5. *

    * Both unary and multi-valued {@link Property}-ies are supported. *

    *

    * Usage example with a unary {@link Property}: *

    {@code
         *    Optional price = nodeProperties.propertyValue("price", DefaultProperties.LONG_CLASS);
         *    Optional name = nodeProperties.propertyValue("name", DefaultProperties.STRING_CLASS);}
         *    
    * Usage example with a multi-valued {@link Property}: *
    {@code
         *    Optional prices = nodeProperties.propertyValue("prices", DefaultProperties.LONG_CLASS_ARRAY);
         *    Optional names = nodeProperties.propertyValue("names", DefaultProperties.STRING_CLASS_ARRAY);
         *    }
    *
  6. *
* @param propertyName name of the {@link Property} from which the {@link Value} should be retrieved * @param type {@link Class} with the type that should represent the requested {@link Value} and which that * {@link Value} will be cast to * @return {@link Optional} containing the {@link Value} of the specified {@link Property} converted to the * requested type; if the specified {@link Property} does not exist or its {@link Value} cannot be * converted to the requested type, an empty {@link Optional} is returned * @param expected type */ public Optional propertyValue(String propertyName, Class type) { log.trace("Getting '{}' property value for {}", propertyName, this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .map(Resource::getValueMap) .map(WithPrimitiveArrayTranslation::new) .flatMap(valueMapWithTranslation -> valueMapWithTranslation.get(propertyName, type)); } } /** * Retrieves the {@link PropertyType} of the specified {@link Property}. * @param propertyName name of the {@link Property} whose {@link PropertyType} should be retrieved * @return {@link PropertyType} of the specified {@link Property} */ public int propertyType(String propertyName) { log.trace("Getting '{}' property type for {}", propertyName, this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> new ConditionalProperty(propertyName).retrieveFrom(node)) .map(sneaky(Property::getValue)) .map(Value::getType) .orElse(PropertyType.UNDEFINED); } } /** * Checks if the underlying {@link Node} contains a {@link Property} that has the specified name. * @param propertyName name of the hypothetically existent {@link Property} * @return {@code true} if the underlying {@link Node} contains a {@link Property} that has the specified name; * {@code false} otherwise */ public boolean containsProperty(String propertyName) { log.trace("Checking if '{}' contains property of this name: '{}'", this, propertyName); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .map(Resource::getValueMap) .map(valueMap -> valueMap.containsKey(propertyName)) .orElse(false); } } /** * Retrieves the {@link Value} of a {@link Property} of type {@link PropertyType#BINARY} as a {@link File}. * @param propertyName name of the {@link Property} from which the {@link Value} of type {@link PropertyType#BINARY} * should be retrieved * @return {@link Value} of a {@link Property} of type {@link PropertyType#BINARY} as a {@link File}; * empty {@link Optional} is returned if the {@link Property} isn't of type {@link PropertyType#BINARY} * or doesn't exist */ public Optional retrieveFile(String propertyName) { log.trace("Getting the value of the '{}' property as a file. {}", propertyName, this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> new ConditionalProperty(propertyName).retrieveFrom(node)) .map(sneaky(Property::getValue)) .flatMap(this::asBinary) .map(this::asFile); } } /** * Retrieves the {@link DataSize} of a {@link Value} of a {@link Property} of type {@link PropertyType#BINARY}. * @param propertyName name of the {@link Property} of type {@link PropertyType#BINARY} * that contains a {@link Value} whose {@link DataSize} should be retrieved * @return {@link DataSize} of a {@link Value} of a {@link Property} of type {@link PropertyType#BINARY}; * zero-sized {@link DataSize} is returned if the {@link Property} isn't of type {@link PropertyType#BINARY} * or doesn't exist */ public DataSize binarySize(String propertyName) { log.trace("Getting the value of the '{}' property as a file. {}", propertyName, this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> new ConditionalProperty(propertyName).retrieveFrom(node)) .map(sneaky(Property::getValue)) .flatMap(this::asBinary) .map(sneaky(Binary::getSize)) .map(bytes -> new DataSize(bytes, DataUnit.BYTES)) .orElse(new DataSize(0, DataUnit.BYTES)); } } /** *

* Returns all {@link Property}-ies of the underlying {@link Node} as a {@link Map} * of {@link Property} names to {@link Property} {@link Value}-s converted to {@link String}. *

* The following {@link Property}-ies are omitted from the result: *
    *
  1. {@link Property}-ies with {@link Value}-s that cannot be converted to {@link String}
  2. *
  3. {@link Property}-ies of type {@link PropertyType#BINARY}
  4. *
* @return {@link Property}-ies of the underlying {@link Node} as a {@link Map} * of {@link Property} names to {@link Property} {@link Value}-s converted to {@link String} */ public Map all() { log.trace("Retrieving all properties of {}", this); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); return Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .map(Resource::getValueMap) .map(ValueMap::keySet) .orElse(Set.of()) .stream() .filter(propertyName -> propertyType(propertyName) != PropertyType.BINARY) .map(propertyName -> Map.entry( propertyName, propertyValue(propertyName, DefaultProperties.STRING_CLASS)) ) .filter(entry -> entry.getValue().isPresent()) .map(entry -> Map.entry(entry.getKey(), entry.getValue().orElseThrow())) .collect(Collectors.toUnmodifiableMap( Map.Entry::getKey, Map.Entry::getValue, (first, second) -> first) ); } } /** *

* Sets the value of the specified {@link Property} according to the logic described in * {@link Node#setProperty(String, String)}. *

* This operation can overwrite the current {@link PropertyType} of the existing {@link Property} if it differs from * the new {@link PropertyType}. However, such overwriting behavior is supported only to the extent to which * it is supported by the underlying {@link Node#setProperty(String, String)}. * @param name name of the {@link Property} to set * @param value value of the {@link Property} to set * @return {@link Optional} containing this {@link NodeProperties} if the {@link Property} was set successfully; * an empty {@link Optional} is returned if the {@link Property} wasn't set due to any reason */ @SuppressWarnings("PMD.LinguisticNaming") public Optional setProperty(String name, String value) { log.trace("Setting property '{}' to '{}'", name, value); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); Optional result = Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> setProperty(node, name, value)); result.ifPresent(SneakyConsumer.sneaky(nodeProperties -> resourceResolver.commit())); return result; } } /** *

* Sets the value of the specified {@link Property} according to the logic described in * {@link Node#setProperty(String, boolean)}. *

* This operation can overwrite the current {@link PropertyType} of the existing {@link Property} if it differs from * the new {@link PropertyType}. However, such overwriting behavior is supported only to the extent to which * it is supported by the underlying {@link Node#setProperty(String, boolean)}. * @param name name of the {@link Property} to set * @param value value of the {@link Property} to set * @return {@link Optional} containing this {@link NodeProperties} if the {@link Property} was set successfully; * an empty {@link Optional} is returned if the {@link Property} wasn't set due to any reason */ @SuppressWarnings("PMD.LinguisticNaming") public Optional setProperty(String name, boolean value) { log.trace("Setting property '{}' to '{}'", name, value); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); Optional result = Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> setProperty(node, name, value)); result.ifPresent(SneakyConsumer.sneaky(nodeProperties -> resourceResolver.commit())); return result; } } /** *

* Sets the value of the specified {@link Property} according to the logic described in * {@link Node#setProperty(String, long)}. *

* This operation can overwrite the current {@link PropertyType} of the existing {@link Property} if it differs from * the new {@link PropertyType}. However, such overwriting behavior is supported only to the extent to which * it is supported by the underlying {@link Node#setProperty(String, long)}. * @param name name of the {@link Property} to set * @param value value of the {@link Property} to set * @return {@link Optional} containing this {@link NodeProperties} if the {@link Property} was set successfully; * an empty {@link Optional} is returned if the {@link Property} wasn't set due to any reason */ @SuppressWarnings("PMD.LinguisticNaming") public Optional setProperty(String name, long value) { log.trace("Setting property '{}' to '{}'", name, value); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); Optional result = Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> setProperty(node, name, value)); result.ifPresent(SneakyConsumer.sneaky(nodeProperties -> resourceResolver.commit())); return result; } } /** *

* Sets the value of the specified {@link Property} according to the logic described in * {@link Node#setProperty(String, double)}. *

* This operation can overwrite the current {@link PropertyType} of the existing {@link Property} if it differs from * the new {@link PropertyType}. However, such overwriting behavior is supported only to the extent to which * it is supported by the underlying {@link Node#setProperty(String, double)}. * @param name name of the {@link Property} to set * @param value value of the {@link Property} to set * @return {@link Optional} containing this {@link NodeProperties} if the {@link Property} was set successfully; * an empty {@link Optional} is returned if the {@link Property} wasn't set due to any reason */ @SuppressWarnings("PMD.LinguisticNaming") public Optional setProperty(String name, double value) { log.trace("Setting property '{}' to '{}'", name, value); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); Optional result = Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> setProperty(node, name, value)); result.ifPresent(SneakyConsumer.sneaky(nodeProperties -> resourceResolver.commit())); return result; } } /** *

* Sets the value of the specified {@link Property} according to the logic described in * {@link Node#setProperty(String, BigDecimal)}. *

* This operation can overwrite the current {@link PropertyType} of the existing {@link Property} if it differs from * the new {@link PropertyType}. However, such overwriting behavior is supported only to the extent to which * it is supported by the underlying {@link Node#setProperty(String, BigDecimal)}. * @param name name of the {@link Property} to set * @param value value of the {@link Property} to set * @return {@link Optional} containing this {@link NodeProperties} if the {@link Property} was set successfully; * an empty {@link Optional} is returned if the {@link Property} wasn't set due to any reason */ @SuppressWarnings("PMD.LinguisticNaming") public Optional setProperty(String name, BigDecimal value) { log.trace("Setting property '{}' to '{}'", name, value); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); Optional result = Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> setProperty(node, name, value)); result.ifPresent(SneakyConsumer.sneaky(nodeProperties -> resourceResolver.commit())); return result; } } /** *

* Sets the value of the specified {@link Property} according to the logic described in * {@link Node#setProperty(String, Calendar)}. *

* This operation can overwrite the current {@link PropertyType} of the existing {@link Property} if it differs from * the new {@link PropertyType}. However, such overwriting behavior is supported only to the extent to which * it is supported by the underlying {@link Node#setProperty(String, Calendar)}. * @param name name of the {@link Property} to set * @param value value of the {@link Property} to set * @return {@link Optional} containing this {@link NodeProperties} if the {@link Property} was set successfully; * an empty {@link Optional} is returned if the {@link Property} wasn't set due to any reason */ @SuppressWarnings("PMD.LinguisticNaming") public Optional setProperty(String name, Calendar value) { log.trace("Setting property '{}' to '{}'", name, value); try (ResourceResolver resourceResolver = resourceAccess.acquireAccess()) { String jcrPathRaw = jcrPath.get(); Optional result = Optional.ofNullable(resourceResolver.getResource(jcrPathRaw)) .flatMap(resource -> Optional.ofNullable(resource.adaptTo(Node.class))) .flatMap(node -> setProperty(node, name, value)); result.ifPresent(SneakyConsumer.sneaky(nodeProperties -> resourceResolver.commit())); return result; } } @SuppressWarnings("PMD.LinguisticNaming") private Optional setProperty(Node node, String name, String value) { try { node.setProperty(name, value); log.trace("Property '{}' set to '{}' for {}", name, value, this); return Optional.of(this); } catch (@SuppressWarnings("OverlyBroadCatchBlock") RepositoryException exception) { String message = String.format( "Unable to set property '%s' to '%s' for %s", name, value, this ); log.error(message, exception); return Optional.empty(); } } @SuppressWarnings("PMD.LinguisticNaming") private Optional setProperty(Node node, String name, boolean value) { try { node.setProperty(name, value); log.trace("Property '{}' set to '{}' for {}", name, value, this); return Optional.of(this); } catch (@SuppressWarnings("OverlyBroadCatchBlock") RepositoryException exception) { String message = String.format( "Unable to set property '%s' to '%s' for %s", name, value, this ); log.error(message, exception); return Optional.empty(); } } @SuppressWarnings("PMD.LinguisticNaming") private Optional setProperty(Node node, String name, long value) { try { node.setProperty(name, value); log.trace("Property '{}' set to '{}' for {}", name, value, this); return Optional.of(this); } catch (@SuppressWarnings("OverlyBroadCatchBlock") RepositoryException exception) { String message = String.format( "Unable to set property '%s' to '%s' for %s", name, value, this ); log.error(message, exception); return Optional.empty(); } } @SuppressWarnings("PMD.LinguisticNaming") private Optional setProperty(Node node, String name, double value) { try { node.setProperty(name, value); log.trace("Property '{}' set to '{}' for {}", name, value, this); return Optional.of(this); } catch (@SuppressWarnings("OverlyBroadCatchBlock") RepositoryException exception) { String message = String.format( "Unable to set property '%s' to '%s' for %s", name, value, this ); log.error(message, exception); return Optional.empty(); } } @SuppressWarnings("PMD.LinguisticNaming") private Optional setProperty(Node node, String name, BigDecimal value) { try { node.setProperty(name, value); log.trace("Property '{}' set to '{}' for {}", name, value, this); return Optional.of(this); } catch (@SuppressWarnings("OverlyBroadCatchBlock") RepositoryException exception) { String message = String.format( "Unable to set property '%s' to '%s' for %s", name, value, this ); log.error(message, exception); return Optional.empty(); } } @SuppressWarnings("PMD.LinguisticNaming") private Optional setProperty(Node node, String name, Calendar value) { try { node.setProperty(name, value); log.trace("Property '{}' set to '{}' for {}", name, value, this); return Optional.of(this); } catch (@SuppressWarnings("OverlyBroadCatchBlock") RepositoryException exception) { String message = String.format( "Unable to set property '%s' to '%s' for %s", name, value, this ); log.error(message, exception); return Optional.empty(); } } @SneakyThrows private Optional asBinary(Value value) { int valueType = value.getType(); if (valueType == PropertyType.BINARY) { Binary binary = value.getBinary(); return Optional.of(binary); } else { log.trace("Not a binary type"); return Optional.empty(); } } @SneakyThrows private File asFile(Binary binary) { log.trace("Converting binary to a file"); File tempFile = File.createTempFile("jcr-binary_", ".tmp"); tempFile.deleteOnExit(); Path tempFilePath = tempFile.toPath(); try (InputStream inputStream = binary.getStream(); OutputStream outputStream = Files.newOutputStream(tempFilePath)) { IOUtils.copy(inputStream, outputStream); binary.dispose(); } log.trace("Converted binary to a file: {}", tempFile); return tempFile; } @Override public JCRPath jcrPath() { return jcrPath; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy