/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.version;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.Properties;
import java.util.jar.Manifest;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
/**
* Common location to manage the AS based product name and version.
*
*/
public class ProductConfig implements Serializable {
private static final long serialVersionUID = 1L;
private final String name;
private final String version;
private final String consoleSlot;
private boolean isProduct;
public static ProductConfig fromFilesystemSlot(ModuleLoader loader, String home, Map<?, ?> providedProperties) {
return new ProductConfig(loader, getProductConfProperties(home), providedProperties);
}
public static ProductConfig fromKnownSlot(String slot, ModuleLoader loader, Map<?, ?> providedProperties) {
return new ProductConfig(loader, new ProductConfProps(slot), providedProperties);
}
/** @deprecated use {@link #fromFilesystemSlot(ModuleLoader, String, Map)}. May be removed at any time. */
@Deprecated
public ProductConfig(ModuleLoader loader, String home, Map<?, ?> providedProperties) {
this(loader, getProductConfProperties(home), providedProperties);
}
private ProductConfig(ModuleLoader loader, ProductConfProps productConfProps, Map<?, ?> providedProperties) {
String productName = null;
String projectName = null;
String productVersion = null;
String consoleSlot = null;
try {
if (productConfProps.productModuleId != null) {
Module module = loader.loadModule(productConfProps.productModuleId);
InputStream stream = module.getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF");
Manifest manifest = null;
if (stream != null) {
manifest = new Manifest(stream);
}
if (manifest != null) {
productName = manifest.getMainAttributes().getValue("JBoss-Product-Release-Name");
productVersion = manifest.getMainAttributes().getValue("JBoss-Product-Release-Version");
consoleSlot = manifest.getMainAttributes().getValue("JBoss-Product-Console-Slot");
projectName = manifest.getMainAttributes().getValue("JBoss-Project-Release-Name");
}
}
setSystemProperties(productConfProps.miscProperties, providedProperties);
} catch (Exception e) {
// Don't care
}
isProduct = productName != null && !productName.isEmpty() && projectName == null;
name = isProduct ? productName : projectName;
version = productVersion;
this.consoleSlot = consoleSlot;
}
private static String getProductConf(String home) {
final String defaultVal = home + File.separator + "bin" + File.separator + "product.conf";
PrivilegedAction<String> action = new PrivilegedAction<String>() {
public String run() {
String env = System.getenv("JBOSS_PRODUCT_CONF");
if (env == null) {
env = defaultVal;
}
return env;
}
};
return System.getSecurityManager() == null ? action.run() : AccessController.doPrivileged(action);
}
private static ProductConfProps getProductConfProperties(String home) {
Properties props = new Properties();
BufferedReader reader = null;
try {
reader = Files.newBufferedReader(Paths.get(getProductConf(home)), StandardCharsets.UTF_8);
props.load(reader);
} catch (Exception e) {
// Don't care
} finally {
safeClose(reader);
}
return new ProductConfProps(props);
}
/** Solely for use in unit testing */
public ProductConfig(final String productName, final String productVersion, final String consoleSlot) {
this.name = productName;
this.version = productVersion;
this.consoleSlot = consoleSlot;
}
public String getProductName() {
return name;
}
public String getProductVersion() {
return version;
}
public boolean isProduct() {
return isProduct;
}
public String getConsoleSlot() {
return consoleSlot;
}
public String getPrettyVersionString() {
if (name != null) {
return String.format("%s %s (WildFly Core %s)", name, version, Version.AS_VERSION);
}
if (Version.UNKNOWN_CODENAME.equals(Version.AS_RELEASE_CODENAME)) {
return String.format("WildFly Core %s", Version.AS_VERSION);
}
return String.format("WildFly Core %s \"%s\"", Version.AS_VERSION, Version.AS_RELEASE_CODENAME);
}
public String resolveVersion() {
return version != null ? version : Version.AS_VERSION;
}
public String resolveName() {
return name != null ? name : "WildFly";
}
public static String getPrettyVersionString(final String name, String version1, String version2) {
if(name != null) {
return String.format("JBoss %s %s (WildFly %s)", name, version1, version2);
}
return String.format("WildFly %s \"%s\"", version1, version2);
}
private void setSystemProperties(final Properties propConfProps, final Map providedProperties) {
if (propConfProps.size() == 0) {
return;
}
PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
@Override
public Void run() {
for (Map.Entry<Object, Object> entry : propConfProps.entrySet()) {
String key = (String)entry.getKey();
if (!key.equals("slot") && System.getProperty(key) == null) {
//Only set the property if it was not defined by other means
//System properties defined in standalone.xml, domain.xml or host.xml will overwrite
//this as specified in https://issues.jboss.org/browse/AS7-6380
System.setProperty(key, (String)entry.getValue());
//Add it to the provided properties used on reload by the server environment
providedProperties.put(key, entry.getValue());
}
}
return null;
}
};
if (System.getSecurityManager() == null) {
action.run();
} else {
AccessController.doPrivileged(action);
}
}
private static void safeClose(Closeable c) {
if (c != null) try {
c.close();
} catch (Throwable ignored) {}
}
private static class ProductConfProps {
private final Properties miscProperties;
private final ModuleIdentifier productModuleId;
private ProductConfProps(String slot) {
this.productModuleId = slot == null ? null : ModuleIdentifier.create("org.jboss.as.product", slot);
this.miscProperties = new Properties();
}
private ProductConfProps(Properties properties) {
this(properties.getProperty("slot"));
if (productModuleId != null) {
properties.remove("slot");
}
if (!properties.isEmpty()) {
for (String key : properties.stringPropertyNames()) {
this.miscProperties.setProperty(key, properties.getProperty(key));
}
}
}
}
}