Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Carina Utils module
==================

Feel free to support the development with a [**donation**](https://www.paypal.com/donate/?hosted_button_id=MNHYYCYHAKUVA) for the next improvements.

<p align="center">
<a href="https://zebrunner.com/"><img alt="Zebrunner" src="https://github.com/zebrunner/zebrunner/raw/master/docs/img/zebrunner_intro.png"></a>
</p>
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
<repository>
<id>zebrunner_snapshots</id>
<name>zebrunner Snapshots</name>
<url>https://nexus.zebrunner.dev/repository/ce-snapshots/</url>
<url>https://public-nexus.zebrunner.com/repository/ce-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
Expand Down Expand Up @@ -344,7 +344,7 @@
<snapshotRepository>
<id>ZBR_Nexus</id>
<name>Zebrunner Snapshots</name>
<url>https://nexus.zebrunner.dev/repository/ce-snapshots/</url>
<url>https://public-nexus.zebrunner.com/repository/ce-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>
76 changes: 59 additions & 17 deletions src/main/java/com/zebrunner/carina/utils/R.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.concurrent.ConcurrentException;
import org.apache.commons.lang3.concurrent.LazyInitializer;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -58,6 +61,23 @@ public enum R {

private final String resourceFile;

/**
* With some Maven plugins usage (e.g. exec-maven-plugin) SystemClassLoader can
* not 'see' project resources. That's why we need a possibility to choose what
* ClassLoader instance to use.
* todo think about refactoring this code
*/
private static final LazyInitializer<ClassLoader> CLASS_LOADER = new LazyInitializer<>() {
@Override
protected ClassLoader initialize() {
String carinaClassLoader = System.getProperty("carina_class_loader");
if (!StringUtils.isEmpty(carinaClassLoader) && Boolean.valueOf(carinaClassLoader)) {
return R.class.getClassLoader();
}
return ClassLoader.getSystemClassLoader();
}
};

// temporary thread/test properties which is cleaned on afterTest phase for current thread. It can override any value from below R enum maps
private static ThreadLocal<Properties> testProperties = new ThreadLocal<>();
private static final ThreadLocal<Map<String, String>> PROPERTY_OVERWRITE_NOTIFICATIONS = new ThreadLocal<>();
Expand All @@ -71,6 +91,17 @@ public enum R {
reinit();
}

/**
* For internal usage only!
*/
public static ClassLoader getClassLoader() {
try {
return CLASS_LOADER.get();
}catch (ConcurrentException e) {
return ExceptionUtils.rethrow(e);
}
}

public static void reinit() {
for (R resource : values()) {
try {
Expand All @@ -84,7 +115,7 @@ public static void reinit() {

URL overrideResource;
StringBuilder resourceNameBuilder = new StringBuilder(OVERRIDE_SIGN + resource.resourceFile);
while ((overrideResource = ClassLoader.getSystemResource(resourceNameBuilder.toString())) != null) {
while ((overrideResource = CLASS_LOADER.get().getResource(resourceNameBuilder.toString())) != null) {
try (InputStream resourceStream = overrideResource.openStream()) {
properties.load(resourceStream);
resourceNameBuilder.insert(0, OVERRIDE_SIGN);
Expand Down Expand Up @@ -147,7 +178,11 @@ public static void reinit() {
* @return true if at least one resource found, false otherwise
*/
private static boolean isResourceExists(String resourceName) {
return ClassLoader.getSystemResource(resourceName) != null;
try {
return CLASS_LOADER.get().getResource(resourceName) != null;
}catch (ConcurrentException e) {
return ExceptionUtils.rethrow(e);
}
}

/**
Expand All @@ -157,19 +192,22 @@ private static boolean isResourceExists(String resourceName) {
* @return collected properties
*/
private static Properties collect(String resourceName) throws IOException {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Properties assembledProperties = new Properties();
Enumeration<URL> resourceURLs = classLoader.getResources(resourceName);
while (resourceURLs.hasMoreElements()) {
Properties tempProperties = new Properties();
URL url = resourceURLs.nextElement();

try (InputStream stream = url.openStream()) {
tempProperties.load(stream);
assembledProperties.putAll(tempProperties);
try {
Properties assembledProperties = new Properties();
Enumeration<URL> resourceURLs = CLASS_LOADER.get().getResources(resourceName);
while (resourceURLs.hasMoreElements()) {
Properties tempProperties = new Properties();
URL url = resourceURLs.nextElement();

try (InputStream stream = url.openStream()) {
tempProperties.load(stream);
assembledProperties.putAll(tempProperties);
}
}
return assembledProperties;
}catch (ConcurrentException e) {
return ExceptionUtils.rethrow(e);
}
return assembledProperties;
}

R(String resourceKey) {
Expand Down Expand Up @@ -317,10 +355,14 @@ public boolean getBoolean(String key) {
}

public static String getResourcePath(String resource) {
String path = StringUtils.removeStart(ClassLoader.getSystemResource(resource).getPath(), "/");
path = StringUtils.replaceChars(path, "/", "\\");
path = StringUtils.replaceChars(path, "!", "");
return path;
try {
String path = StringUtils.removeStart(CLASS_LOADER.get().getResource(resource).getPath(), "/");
path = StringUtils.replaceChars(path, "/", "\\");
path = StringUtils.replaceChars(path, "!", "");
return path;
}catch (ConcurrentException e) {
return ExceptionUtils.rethrow(e);
}
}

public Properties getProperties() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.zebrunner.carina.utils.config;

import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

Expand All @@ -9,10 +11,16 @@
import com.zebrunner.carina.utils.R;
import com.zebrunner.carina.utils.encryptor.EncryptorUtils;
import com.zebrunner.carina.utils.exception.InvalidConfigurationException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.mutable.Mutable;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.commons.lang3.reflect.ConstructorUtils;

public class Configuration {
private static final String REQUIRE_VALUE_ERROR_MESSAGE = "Getting the value of parameter '%s' as required failed: the value is missing.";

private static final MutableObject<IEnvArgResolver> ENV_ARG_RESOLVER = new MutableObject<>(new DefaultEnvArgResolver());

public enum Parameter implements IParameter {

/**
Expand Down Expand Up @@ -106,7 +114,7 @@ protected static Optional<String> getEnvironmentParameter(String parameter) {
return Optional.empty();
}

String value = R.CONFIG.get(environment + "." + parameter);
String value = ENV_ARG_RESOLVER.getValue().get(environment, parameter);
if (value == null || "NULL".equalsIgnoreCase(value) || value.isEmpty()) {
return Optional.empty();
}
Expand Down Expand Up @@ -193,6 +201,14 @@ public static <T> T getRequired(String parameter, Class<T> clazz, ConfigurationO
String.format(REQUIRE_VALUE_ERROR_MESSAGE, parameter)));
}

public static void setEnvironmentArgumentResolver(Class<? extends IEnvArgResolver> clazz) {
try {
ENV_ARG_RESOLVER.setValue(ConstructorUtils.invokeConstructor(Objects.requireNonNull(clazz)));
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException | InstantiationException e) {
ExceptionUtils.rethrow(e);
}
}

protected Optional<String> asString(IParameter[] parameters) {
String lineFormat = "%s=%s%n";
StringBuilder asString = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.zebrunner.carina.utils.config;

public class DefaultEnvArgResolver implements IEnvArgResolver {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.zebrunner.carina.utils.config;

import com.zebrunner.carina.utils.R;

public interface IEnvArgResolver {

default String get(String env, String key) {
return R.CONFIG.get(env + "." + key);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*******************************************************************************
* Copyright 2020-2022 Zebrunner Inc (https://www.zebrunner.com).
*
* 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 com.zebrunner.carina.utils.resources;

import java.net.URL;

public interface ResourceURLFilter {
boolean accept(URL resourceUrl);
}
96 changes: 96 additions & 0 deletions src/main/java/com/zebrunner/carina/utils/resources/Resources.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package com.zebrunner.carina.utils.resources;

import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.util.HashSet;
import java.util.Set;

import com.zebrunner.carina.utils.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class Resources {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

private Resources() {
}

private static void collectURL(ResourceURLFilter f, Set<URL> s, URL u) {
if (f == null || f.accept(u)) {
LOGGER.debug("adding resource url by filter: {}", u);
s.add(u);
}
}

private static void iterateFileSystem(File r, ResourceURLFilter f,
Set<URL> s) {
File[] files = r.listFiles();
for (File file : files) {
if (file.isDirectory()) {
iterateFileSystem(file, f, s);
} else if (file.isFile()) {
try {
collectURL(f, s, file.toURI().toURL());
} catch (MalformedURLException e) {
LOGGER.debug("Error while collecting urls!", e);
}
}
}
}

private static void iterateEntry(File p, ResourceURLFilter f, Set<URL> s) {
if (p.isDirectory()) {
iterateFileSystem(p, f, s);
}
}

// To scan the entire class path and return all its resources as URLs
public static Set<URL> getResourceURLs() {
return getResourceURLs((ResourceURLFilter) null);
}

// To scan the class path starting with the location from which a specific
// class was loaded, provide the getResourceURLs method with the root-class
@SuppressWarnings("rawtypes")
public static Set<URL> getResourceURLs(Class rootClass) {
return getResourceURLs(rootClass, null);
}

public static Set<URL> getResourceURLs(ResourceURLFilter filter) {
Set<URL> collectedURLs = new HashSet<>();
try (URLClassLoader ucl = new URLClassLoader(new URL[] { (R.getClassLoader()).getResource("L10N") },
R.getClassLoader())) {
for (URL url : ucl.getURLs()) {
try {
iterateEntry(new File(url.toURI()), filter, collectedURLs);
} catch (URISyntaxException e) {
LOGGER.debug("Error during creating URI from url!", e);
}
}
return collectedURLs;
} catch (IOException e) {
LOGGER.debug("Error on creating URLClassLoader!", e);
}
return collectedURLs;
}

@SuppressWarnings("rawtypes")
public static Set<URL> getResourceURLs(Class rootClass,
ResourceURLFilter filter) {
Set<URL> collectedURLs = new HashSet<>();
CodeSource src = rootClass.getProtectionDomain().getCodeSource();
try {
iterateEntry(new File(src.getLocation().toURI()), filter,
collectedURLs);
} catch (URISyntaxException e) {
LOGGER.debug("Error during creating URI from url!", e);
}
return collectedURLs;
}
}