
net.adamcin.oakpal.core.Util Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oakpal-core Show documentation
Show all versions of oakpal-core Show documentation
OakPAL Core Implementation
/*
* Copyright 2018 Mark Adamcin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.adamcin.oakpal.core;
import aQute.bnd.header.Attrs;
import aQute.bnd.header.Parameters;
import aQute.bnd.osgi.Domain;
import net.adamcin.oakpal.core.jcrfacade.SessionFacade;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Session;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public final class Util {
private static final Logger LOGGER = LoggerFactory.getLogger(Util.class);
private Util() {
// do nothing
}
static boolean isEmpty(final String value) {
return value == null || value.isEmpty();
}
/**
* Public utility method to wrap an existing session with a facade that blocks writes.
*
* @param session the existing session to wrap
* @return a read-only session
*/
public static Session wrapSessionReadOnly(final Session session) {
return SessionFacade.findBestWrapper(session, false);
}
public static List getManifestHeaderValues(final Manifest manifest, final String headerName) {
Domain domain = Domain.domain(manifest);
Parameters params = domain.getParameters(headerName);
return new ArrayList<>(params.keySet());
}
public static String escapeManifestHeaderValue(final @NotNull String... values) {
return escapeManifestHeaderValues(Arrays.asList(values));
}
public static String escapeManifestHeaderValues(final @NotNull List values) {
Parameters parameters = new Parameters();
values.stream().forEachOrdered(value -> parameters.put(value, new Attrs()));
return parameters.toString();
}
public static List resolveManifestResources(final URL manifestUrl, final List resources) {
return resources.stream()
.map(name -> name.contains(":") ? name : "../" + name)
.flatMap(composeTry(Stream::of, Stream::empty,
(relPath) -> new URL(manifestUrl, relPath),
(relPath, error) ->
LOGGER.debug("[resolveManifestResources] malformed url: manifestUrl={}, relPath={}, error={}",
manifestUrl, relPath, error.getMessage())))
.collect(Collectors.toList());
}
public static Map> mapManifestHeaderResources(final String headerName, final ClassLoader classLoader) throws IOException {
Map> map = new LinkedHashMap<>();
Enumeration resEnum = classLoader.getResources(JarFile.MANIFEST_NAME);
while (resEnum.hasMoreElements()) {
URL url = resEnum.nextElement();
try (InputStream is = url.openStream()) {
Manifest manifest = new Manifest(is);
List headerResources = resolveManifestResources(url, getManifestHeaderValues(manifest, headerName));
map.put(url, headerResources);
}
}
return map;
}
public static Map> mapManifestHeaderResources(final String headerName, final List files) throws IOException {
Map> map = new LinkedHashMap<>();
for (File zipFile : files) {
if (!zipFile.exists() || zipFile.isDirectory()) {
File manifestFile = new File(zipFile, JarFile.MANIFEST_NAME);
if (manifestFile.exists()) {
try (InputStream fis = new FileInputStream(manifestFile)) {
Manifest manifest = new Manifest(fis);
final URL manifestUrl = manifestFile.toURI().toURL();
map.put(manifestUrl, resolveManifestResources(manifestUrl,
getManifestHeaderValues(manifest, headerName)));
}
}
} else {
try (JarFile jar = new JarFile(zipFile)) {
Manifest manifest = jar.getManifest();
final URL manifestUrl = new URL(String.format("jar:%s!/%s",
zipFile.toURI().toURL().toExternalForm(), JarFile.MANIFEST_NAME));
map.put(manifestUrl, resolveManifestResources(manifestUrl,
getManifestHeaderValues(manifest, headerName)));
}
}
}
return map;
}
public static Map> mapManifestHeaderResources(final String headerName, final URL manifestUrl) throws IOException {
Map> map = new LinkedHashMap<>();
try (InputStream is = manifestUrl.openStream()) {
Manifest manifest = new Manifest(is);
map.put(manifestUrl, resolveManifestResources(manifestUrl,
getManifestHeaderValues(manifest, headerName)));
}
return map;
}
static ClassLoader getDefaultClassLoader() {
return Thread.currentThread().getContextClassLoader() != null
? Thread.currentThread().getContextClassLoader()
: Util.class.getClassLoader();
}
/**
* Logger function to inject into a stream by way of {@code filter()} method. Calls {@code logger.debug()} with the
* provided {@code format} string and the current stream element as a format argument.
*
* @param logger the logger to use
* @param format the SLF4j format string (use curly braces for placeholders)
* @param the captured type parameter for the stream element
* @return a single-argument predicate for use in a {@code Stream.filter()} method
*/
public static Predicate debugFilter(final Logger logger, final String format) {
return item -> {
logger.debug(format, item);
return true;
};
}
/**
* Logger function to inject into a stream by way of {@code filter()} method. Calls {@code logger.trace()} with the
* provided {@code format} string and the current stream element as a format argument.
*
* @param logger the logger to use
* @param format the SLF4j format string (use curly braces for placeholders)
* @param the captured type parameter for the stream element
* @return a single-argument predicate for use in a {@code Stream.filter()} method
*/
public static Predicate traceFilter(final Logger logger, final String format) {
return item -> {
logger.trace(format, item);
return true;
};
}
/**
* Composes four lambdas into a single function for use with flatMap() defined by {@link Stream},
* {@link java.util.Optional}, etc. Useful for eliminating clumsy try/catch blocks from lambdas.
*
* @param monadUnit the "unit" (or "single") function defined by the appropriate monad. I.E. Stream::of,
* Optional::of, or Optional::ofNullable.
* @param monadZero the "zero" (or "empty") function defined by the appropriate monad, as in Stream::empty,
* or Optional::empty
* @param onElement some function that produces type {@code R} when given an object of type {@code T}, or fails
* with an Exception.
* @param onError an optional consumer function to perform some logic when the parser function throws.
* Receives both the failing input element and the caught Exception.
* @param The captured monad type, which must match the return types of the {@code monadUnit} and
* {@code monadZero} functions, but which is not involved in the {@code onElement} or
* {@code onError} functions.
* @param The input type mapped by the monad, i.e. the String type in {@code Stream}.
* @param The output type mapped by the monad, i.e. the URL type in {@code Stream}.
* @return a flatMappable function
* @see Fun#composeTry(Function, Supplier, Fun.ThrowingFunction, BiConsumer)
* @deprecated 1.3.0 use {@link Fun#composeTry(Function, Supplier, Fun.ThrowingFunction, BiConsumer)}
*/
@Deprecated
public static Function composeTry(final Function monadUnit,
final Supplier monadZero,
final TryFunction onElement,
final BiConsumer onError) {
return Fun.composeTry(monadUnit, monadZero, onElement, onError);
}
/**
* Functional interface similar to {@link Function}, but which allows for throwing exceptions. Use with
* {@link #composeTry(Function, Supplier, TryFunction, BiConsumer)} to make suitable for {@code flatMap}.
*
* @param input type
* @param output type
* @deprecated 1.3.0 use {@link Fun.ThrowingFunction}
*/
@Deprecated
public interface TryFunction extends Fun.ThrowingFunction {
}
/**
* Compose a function with {@code Optional::ofNullable} to wrap the output type.
*
* @param inputFunc the input function
* @param input type
* @param input function return type
* @return a function returning an optional of the input function return type
* @deprecated 1.3.0 use {@code Fun.compose(Optional::ofNullable, inputFunc)}
*/
@Deprecated
public static Function> optFunc(final Function inputFunc) {
return ((Function>) Optional::ofNullable).compose(inputFunc);
}
/**
* Compose two functions, left-to-right.
*
* @param before the left function
* @param after the right function
* @param the input type
* @param the intermediate type
* @param the output type
* @return a composed function from {@code T} to {@code R}
* @deprecated 1.3.0 use {@link Fun#compose(Function, Function)} instead
*/
@Deprecated
public static Function compose(final Function before, final Function after) {
return after.compose(before);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy