net.oneandone.lavender.modules.ModuleProperties Maven / Gradle / Ivy
/*
* Copyright 1&1 Internet AG, https://github.com/1and1/
*
* 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.oneandone.lavender.modules;
import net.oneandone.lavender.config.PropertiesBase;
import net.oneandone.lavender.config.Secrets;
import net.oneandone.sushi.fs.FileNotFoundException;
import net.oneandone.sushi.fs.Node;
import net.oneandone.sushi.fs.file.FileNode;
import net.oneandone.sushi.fs.filter.Filter;
import net.oneandone.sushi.util.Separator;
import net.oneandone.sushi.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/** represents module (or application module) properties */
public class ModuleProperties extends PropertiesBase {
private static final Logger LOG = LoggerFactory.getLogger(ModuleProperties.class);
public static final String MODULE_PROPERTIES = "META-INF/lavender.properties";
private static final String APP_PROPERTIES = "WEB-INF/lavender.properties";
private static final List DEFAULT_INCLUDES = new ArrayList<>(Arrays.asList(
"**/*.gif", "**/*.png", "**/*.jpg", "**/*.jpeg", "**/*.ico", "**/*.swf", "**/*.css", "**/*.js"));
public static Filter defaultFilter() {
return new Filter().include(DEFAULT_INCLUDES);
}
//--
public static ModuleProperties loadApp(boolean prod, Node webapp, List legacy) throws IOException {
Node src;
Properties pominfo;
Properties properties;
src = webapp.join(ModuleProperties.APP_PROPERTIES);
src.checkFile();
pominfo = pominfoOpt(webapp.join("WEB-INF/classes"));
if (pominfo == null) {
// TODO: try target/classes - hack because pws deletes WEB-INF/classes to get virtual classpath working
pominfo = pominfoOpt(webapp.join("../classes"));
}
if (pominfo == null) {
throw new IOException("pominfo.properties for application not found");
}
properties = src.readProperties();
if (properties.containsKey("pustefix.relative")) {
LOG.info("loading legacy application configuration");
try {
legacy.addAll(NodeModule.scanLegacy(webapp));
} catch (Exception e) {
throw new IOException("failed to check legacy applications: " + e.getMessage(), e);
}
throw new IOException("legacy apps no longer supported");
} else {
legacy.addAll(Separator.COMMA.split(PropertiesBase.eatOpt(properties, "legacy", "")));
if (!legacy.isEmpty()) {
throw new IOException("legacy modules no longer supported");
}
LOG.info("legacy modules: " + legacy);
return parse(prod, properties, pominfo);
}
}
public static ModuleProperties loadModule(boolean prod, Node root, Node pominfo) throws IOException {
return ModuleProperties.parse(prod, root.readProperties(), pominfo.readProperties());
}
public static ModuleProperties loadModuleOpt(boolean prod, Node root) throws IOException {
Node src;
if (root == null) {
return null;
}
src = root.join(ModuleProperties.MODULE_PROPERTIES);
if (!src.exists()) {
return null;
}
return ModuleProperties.parse(prod, src.readProperties(), pominfoOpt(root));
}
private static Properties pominfoOpt(Node root) throws IOException {
try {
return root.join(PustefixJar.POMINFO_PROPERTIES).readProperties();
} catch (FileNotFoundException e) {
return null;
}
}
// public only for testing
public static ModuleProperties parse(boolean prod, Properties properties, Properties pominfo) throws IOException {
ModuleProperties result;
String relative;
String source;
String scmurlProd;
String scmurlDevel;
String tag;
String scmsrc;
if (pominfo == null) {
throw new IOException("pominfo.properties for module not found: " + properties);
}
relative = eatOpt(properties, "pustefix.relative", null);
if (!prod && thisMachine(pominfo.getProperty("ethernet"))) {
source = pominfo.getProperty("basedir");
} else {
source = null;
}
result = new ModuleProperties();
if (relative != null) {
// legacy descriptor
checkUnmatchable(eatFilter(properties, "pustefix", DEFAULT_INCLUDES));
for (String prefix : prefixes(properties, ScmProperties.SVN_PREFIX)) {
String scmSvn = "scm:svn:";
scmurlProd = (String) properties.remove(prefix);
if (!scmurlProd.startsWith(scmSvn)) { // work-around missing scmsvn prefix when released with prerelease plugin
scmurlProd = scmSvn + scmurlProd;
}
scmurlDevel = eatOpt(properties, prefix + ".devel", scmurlProd);
if (!scmurlDevel.startsWith(scmSvn)) { // work-around missing scmsvn prefix when released with prerelease plugin
scmurlDevel = scmSvn + scmurlDevel;
}
tag = eatOpt(properties, prefix + ".revision", "-1");
scmsrc = eatLegacySvnSource(properties, prefix, source == null ? null : join(source, relative));
scmsrc = fallback(scmurlProd, scmsrc);
result.configs.add(
new ScmProperties(
prefix.substring(prefix.indexOf('.') + 1),
eatFilter(properties, prefix, DEFAULT_INCLUDES),
scmurlProd, scmurlDevel, tag, "",
eatOpt(properties, prefix + ".type", Module.TYPE),
eatBoolean(properties, prefix + ".lavendelize", true),
eatOpt(properties, prefix + ".resourcePathPrefix", ""),
eatOpt(properties, prefix + ".targetPathPrefix", ""),
scmsrc));
}
} else {
for (String prefix : prefixes(properties, ScmProperties.SCM_PREFIX)) {
scmurlProd = (String) properties.remove(prefix);
scmurlDevel = eatOpt(properties, prefix + ".devel", scmurlProd);
tag = eatOpt(properties, prefix + ".tag", "");
String path = eatOpt(properties, prefix + ".path", "");
if (!path.isEmpty() && !path.startsWith("/")) {
path = "/" + path;
}
scmsrc = fallback(scmurlProd, source == null ? null : join(source, path));
result.configs.add(
new ScmProperties(
prefix.substring(prefix.indexOf('.') + 1),
eatFilter(properties, prefix, DEFAULT_INCLUDES),
scmurlProd, scmurlDevel, tag, path,
eatOpt(properties, prefix + ".type", Module.TYPE),
eatBoolean(properties, prefix + ".lavendelize", true),
eatOpt(properties, prefix + ".resourcePathPrefix", ""),
eatOpt(properties, prefix + ".targetPathPrefix", ""),
scmsrc));
}
}
if (properties.size() > 0) {
throw new IllegalArgumentException("unknown properties: " + properties);
}
return result;
}
private static void checkUnmatchable(Filter filter) {
String[] array;
array = filter.getExcludes();
if (array.length != 1 || !"**/*".equals(array[0])) {
throw new UnsupportedOperationException("unsupported filter: " + Arrays.asList(filter.getExcludes()));
}
}
private static String eatLegacySvnSource(Properties properties, String prefix, String source) {
String relative;
relative = eatOpt(properties, prefix + ".relative", null);
return source == null || relative == null ? null : join(source, relative);
}
private static String join(String left, String right) {
StringBuilder result;
result = new StringBuilder(left);
if (!left.endsWith("/")) {
result.append("/");
}
if (right.startsWith("/")) {
right = right.substring(1);
}
result.append(right);
return result.toString();
}
private static Filter eatFilter(Properties properties, String prefix, List defaultIncludes) {
Filter result;
result = new Filter();
result.include(eatListOpt(properties, prefix + ".includes", defaultIncludes));
result.exclude(eatListOpt(properties, prefix + ".excludes", Collections.EMPTY_LIST));
return result;
}
private static List eatListOpt(Properties p, String key, List dflt) {
String result;
result = eatOpt(p, key, null);
return result == null ? dflt : Separator.COMMA.split(result);
}
private static List prefixes(Properties properties, String prefix) {
List result;
result = new ArrayList<>();
for (String name : properties.stringPropertyNames()) {
if (name.startsWith(prefix)) {
if (Strings.count(name, ".") == 1) {
result.add(name);
}
}
}
return result;
}
//--
public final Collection configs;
public ModuleProperties() {
this.configs = new ArrayList<>();
}
public void createModules(FileNode cache, boolean prod, Secrets secrets, List result, PustefixJarConfig jarConfig)
throws IOException {
for (ScmProperties config : configs) {
result.add(config.create(cache, prod, secrets, jarConfig));
}
}
//--
private static boolean thisMachine(String ethernet) throws IOException {
List thisEthernet;
List otherEthernet;
thisEthernet = ethernet();
otherEthernet = Separator.COMMA.split(ethernet);
for (String address : thisEthernet) {
if (otherEthernet.contains(address)) {
return true;
}
}
return false;
}
public static List ethernet() throws IOException {
Enumeration ifcs;
List result;
NetworkInterface ifc;
byte[] address;
ifcs = NetworkInterface.getNetworkInterfaces();
result = new ArrayList<>();
while (ifcs.hasMoreElements()) {
ifc = (NetworkInterface) ifcs.nextElement();
address = ifc.getHardwareAddress();
if (address != null) {
result.add(toHex(address));
} else {
// ignore -- not available (i.e. loopback device) or not accessible
}
}
return result;
}
private static String toHex(byte... bytes) {
StringBuilder builder;
builder = new StringBuilder();
for (byte b : bytes) {
if (builder.length() > 0) {
builder.append(':');
}
builder.append(toHexChar(b >> 4 & 0xf));
builder.append(toHexChar(b & 0xf));
}
return builder.toString();
}
private static char toHexChar(int b) {
if (b >= 0 && b <= 9) {
return (char) ('0' + b);
} else if (b >= 10 && b <= 15) {
return (char) ('a' + b - 10);
} else {
throw new IllegalArgumentException("" + b);
}
}
//--
private static final Map FALLBACK_SOURCES;
static {
String str;
int idx;
String file;
FALLBACK_SOURCES = new HashMap<>();
str = System.getenv("LAVENDER_FALLBACKS");
if (str != null) {
for (String entry : Separator.COMMA.split(str)) {
idx = entry.indexOf('=');
if (idx == -1) {
throw new IllegalStateException("illegal fallback entry: " + entry);
}
file = entry.substring(idx + 1);
if (!new java.io.File(file).isDirectory()) {
throw new IllegalStateException("fallback directory not found: " + file);
}
FALLBACK_SOURCES.put(entry.substring(0, idx), file);
}
LOG.info("fallback configured: " + FALLBACK_SOURCES);
}
}
private static String fallback(String url, String source) {
String fallbackSource;
fallbackSource = FALLBACK_SOURCES.get(url);
if (!FALLBACK_SOURCES.isEmpty()) {
LOG.info("fallback for url " + url + ": " + fallbackSource);
}
return fallbackSource != null ? fallbackSource : source;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy