org.nuiton.i18n.I18nUtil Maven / Gradle / Ivy
/*
* #%L
* I18n :: Runtime
* %%
* Copyright (C) 2018 Code Lutin, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nuiton.i18n;
import io.ultreia.java4all.i18n.runtime.format.I18nMessageFormatter;
import io.ultreia.java4all.i18n.runtime.format.StringFormatI18nMessageFormatter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipFile;
/** @author Tony Chemit - [email protected] */
public class I18nUtil {
public static final String ISO_8859_1_ENCONDING = "ISO-8859-1";
public static final String UTF_8_ENCONDING = "UTF-8";
public static final String DEFAULT_ENCODING = UTF_8_ENCONDING;
public static final Charset DEFAULT_CHARSET =
Charset.forName(DEFAULT_ENCODING);
public static final I18nMessageFormatter DEFAULT_MESSAGE_FORMATTER =
new StringFormatI18nMessageFormatter();
public static final String[] EMPTY_STRING_ARRAY = new String[0];
/** Logger. */
private static final Logger log = LogManager.getLogger(I18nUtil.class);
/**
* Test if an url contains the given directory with no recurse seeking.
*
* @param url the url to seek
* @param directory the directory to find
* @return {@code true} if directory was found, {@code false} otherwise.
* @throws IOException if any io pb
*/
public static boolean containsDirectDirectory(URL url, String directory) throws IOException {
String fileName = url.getFile();
// TODO deal with encoding in windows, this is very durty,
// TODO but it works...
File file = new File(fileName.replaceAll("%20", " "));
if (!file.exists()) {
return false;
}
if (isJar(fileName) || isZip(fileName)) {
// cas ou le fichier du classLoader est un fichier jar ou zip
if (log.isTraceEnabled()) {
log.trace("zip to search " + file);
}
return new ZipFile(file).getEntry(directory + "/") != null;
}
if (file.isDirectory()) {
// cas ou le ichier du classLoader est un repertoire
if (log.isTraceEnabled()) {
log.trace(String.format("directory to search %s", file));
}
return new File(file, directory).exists();
}
if (log.isWarnEnabled()) {
log.warn(String.format("unknown resource type %s", url));
}
return false;
}
/**
* Verifie si le fichier est un fichier jar.
*
* @param name nom du fichier a tester
* @return vrai si le fichier se termine par .jar faux sinon
*/
public static boolean isJar(String name) {
if (name != null && name.length() > 4) {
String ext = name.substring(name.length() - 4, name.length());
return ".jar".equalsIgnoreCase(ext);
}
return false;
}
/**
* Verifie si le fichier est un fichier zip
*
* @param name nom du fichier a tester
* @return vrai si le fichier se termine par .zip faux sinon
*/
public static boolean isZip(String name) {
if (name != null && name.length() > 4) {
String ext = name.substring(name.length() - 4, name.length());
return ".zip".equalsIgnoreCase(ext);
}
return false;
}
/**
* Retourne la liste des fichiers correspondant au pattern donne, aucun
* ordre ne doit être supposé sur les fichiers.
*
* @param repository repertoire dans lequel on recherche les fichiers
* @param pattern le nom du fichier a extraire du fichier du repertoire
* doit correspondre au pattern (repertoire + nom
* compris). si le pattern est null, tous les fichiers
* trouvé sont retourné.
* @return la liste des urls correspondant au pattern
*/
public static List getURLsFromDirectory(File repository, String pattern) {
try {
if (log.isTraceEnabled()) {
log.trace(String.format("search '%s' in %s", pattern, repository));
}
List urlList = new ArrayList<>();
File[] filesList = repository.listFiles();
if (filesList != null) {
for (File file : filesList) {
String name = file.getAbsolutePath();
if (log.isTraceEnabled()) {
log.trace(String.format("directory: %s name: %s", repository, name));
}
// cas de recursivite : repertoire dans un repertoire
if (file.exists() && file.isDirectory()) {
urlList.addAll(getURLsFromDirectory(file,
pattern));
// si le fichier du repertoire n'est pas un repertoire
// on verifie s'il correspond au pattern
} else if (pattern == null || name.matches(pattern)) {
URL url = file.toURI().toURL();
if (log.isTraceEnabled()) {
log.trace(String.format("directory: %s url: %s", repository, url));
}
urlList.add(url);
}
}
}
if (log.isTraceEnabled()) {
log.trace(String.format("found with pattern '%s' : %s", pattern, urlList));
}
return urlList;
} catch (MalformedURLException eee) {
throw new IllegalArgumentException(
String.format("Erreur lors de la conversion de l'url %s (pattern %s) %s", repository, pattern, eee.getMessage()), eee);
}
}
/**
* Returns the all urls to be used in a {@link URLClassLoader}.
*
* If classloader has only one url and the url is a jar, try to load in
* manifest class-path.
*
* @param loader the classloader (if null will use system one)
* @return all the url found in the classloader
*/
public static URL[] getDeepURLs(URLClassLoader loader) {
Stack urlToTreate = new Stack<>();
List urlTreated = new ArrayList<>();
// first get the urls from classloader
URL[] result = getURLs(loader);
urlToTreate.addAll(Arrays.asList(result));
while (!urlToTreate.isEmpty()) {
URL currentUrl = urlToTreate.pop();
// save the url
urlTreated.add(currentUrl);
if (isJar(currentUrl.toString())) {
// jar invocation
try {
URL[] newArrayURLs = getClassPathURLsFromJarManifest(currentUrl);
if (newArrayURLs == null) {
continue;
}
List newURLs = Arrays.asList(newArrayURLs);
for (URL newURL : newURLs) {
if (!urlTreated.contains(newURL) && !urlToTreate.contains(newURL)) {
urlToTreate.add(newURL);
}
}
} catch (Exception e) {
if (log.isDebugEnabled()) {
// this is not a such error, but some jar can not be
log.debug(String.format("error with url%s for reason : %s", currentUrl, e.getMessage()));
}
}
}
}
return urlTreated.toArray(new URL[urlToTreate.size()]);
}
/**
* Recupere la liste des urls d'un {@link URLClassLoader}.
*
* Note : Un cas particulier est positionné pour JBoss qui utilise la method
* getAllURLs.
*
* @param classLoader le class loader a scanner
* @return les urls du classloade.
*/
public static URL[] getURLs(URLClassLoader classLoader) {
if (classLoader == null) {
classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
}
Method m;
try {
// Essai de récupération de la méthode getAllURLs() de
// RepositoryClassLoader (JBoss)
m = classLoader.getClass().getMethod("getAllURLs");
} catch (Exception e) {
m = null;
}
URL[] result;
if (m == null) {
result = classLoader.getURLs();
} else {
try {
result = (URL[]) m.invoke(classLoader);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
return result;
}
public static URL[] getClassPathURLsFromJarManifest(URL jarURL) throws IOException, URISyntaxException {
JarFile jar = null;
URL[] result;
try {
String jarPath = jarURL.toURI().getPath();
File jarFile = new File(jarPath);
if (log.isDebugEnabled()) {
log.debug("class-path jar to scan " + jarPath);
}
jar = new JarFile(jarFile);
File container = jarFile.getParentFile();
Manifest mf = jar.getManifest();
String classPath = null;
if (mf != null && mf.getMainAttributes() != null) {
classPath = mf.getMainAttributes().getValue(Attributes.Name.CLASS_PATH);
}
String[] paths;
if (classPath != null) {
paths = classPath.split(" ");
} else {
paths = EMPTY_STRING_ARRAY;
}
result = new URL[paths.length + 1];
result[0] = jarURL;
File path;
for (int i = 0; i < paths.length; i++) {
String s = paths[i];
// test de l'existence d'un protocole dans le path (genre file:...)
if (s.indexOf(':') != -1) {
result[i + 1] = new URL(s);
continue;
}
if (s.startsWith(".") || !s.startsWith("/")) {
// relative url
path = new File(container, s);
} else {
path = new File(s);
}
if (log.isDebugEnabled()) {
log.debug(path);
}
result[i + 1] = path.toURI().toURL();
}
jar.close();
} finally {
if (jar != null) {
jar.close();
}
}
return result;
}
}