Java tutorial
/* * Artifactory is a binaries repository manager. * Copyright (C) 2012 JFrog Ltd. * * Artifactory 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. * * Artifactory 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 Artifactory. If not, see <http://www.gnu.org/licenses/>. */ package org.artifactory.common; import com.google.common.base.Charsets; import com.google.common.io.Files; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.artifactory.common.ha.ClusterProperties; import org.artifactory.common.ha.HaNodeProperties; import org.artifactory.common.property.ArtifactorySystemProperties; import org.artifactory.mime.MimeTypes; import org.artifactory.mime.MimeTypesReader; import org.artifactory.version.ArtifactoryVersionReader; import org.artifactory.version.CompoundVersionDetails; import javax.annotation.Nullable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * @author yoavl */ public class ArtifactoryHome { public static final String SYS_PROP = "artifactory.home"; public static final String SERVLET_CTX_ATTR = "artifactory.home.obj"; public static final String STORAGE_PROPS_FILE_NAME = "storage.properties"; public static final String MISSION_CONTROL_FILE_NAME = "mission.control.properties"; public static final String ARTIFACTORY_CONVERTER_OBJ = "artifactory.converter.manager.obj"; public static final String ARTIFACTORY_VERSION_PROVIDER_OBJ = "artifactory.version.provider.obj"; public static final String ARTIFACTORY_CONFIG_FILE = "artifactory.config.xml"; public static final String ARTIFACTORY_CONFIG_BOOTSTRAP_FILE = "artifactory.config.bootstrap.xml"; public static final String ARTIFACTORY_SYSTEM_PROPERTIES_FILE = "artifactory.system.properties"; public static final String ARTIFACTORY_PROPERTIES_FILE = "artifactory.properties"; public static final String LOGBACK_CONFIG_FILE_NAME = "logback.xml"; public static final String MIME_TYPES_FILE_NAME = "mimetypes.xml"; public static final String ARTIFACTORY_HA_NODE_PROPERTIES_FILE = "ha-node.properties"; public static final String CLUSTER_PROPS_FILE = "cluster.properties"; private static final String ENV_VAR = "ARTIFACTORY_HOME"; private static final String ARTIFACTORY_CONFIG_LATEST_FILE = "artifactory.config.latest.xml"; private static final String ARTIFACTORY_CONFIG_IMPORT_FILE = "artifactory.config.import.xml"; private static final InheritableThreadLocal<ArtifactoryHome> current = new InheritableThreadLocal<>(); private final File homeDir; private MimeTypes mimeTypes; private ArtifactorySystemProperties artifactorySystemProperties; private HaNodeProperties HaNodeProperties; private ClusterProperties clusterProperties; private File etcDir; private File dataDir; private File logDir; private File backupDir; private File tempWorkDir; private File supportDir; private File tempUploadDir; private File pluginsDir; private File logoDir; private File haEtcDir; private File haDataDir; private File haBackupDir; /** * protected constructor for testing usage only. */ protected ArtifactoryHome() { homeDir = null; } public ArtifactoryHome(SimpleLog logger) { String homeDirPath = findArtifactoryHome(logger); homeDir = new File(homeDirPath); create(); } public ArtifactoryHome(File homeDir) { if (homeDir == null) { throw new IllegalArgumentException("Home dir path cannot be null"); } this.homeDir = homeDir; create(); } private static void checkWritableDirectory(File dir) { if (!dir.exists() || !dir.isDirectory() || !dir.canWrite()) { String message = "Directory '" + dir.getAbsolutePath() + "' is not writable!"; System.out.println(ArtifactoryHome.class.getName() + " - Warning: " + message); throw new IllegalArgumentException(message); } } public static boolean isBound() { return current.get() != null; } public static ArtifactoryHome get() { ArtifactoryHome home = current.get(); if (home == null) { throw new IllegalStateException("Artifactory home is not bound to the current thread."); } return home; } public static void bind(ArtifactoryHome props) { current.set(props); } public static void unbind() { current.remove(); } public File getHomeDir() { return homeDir; } public File getDataDir() { return dataDir; } public File getEtcDir() { return etcDir; } public File getHaAwareEtcDir() { return haEtcDir != null ? haEtcDir : etcDir; } public File getHaAwareDataDir() { return haDataDir != null ? haDataDir : dataDir; } public File getHaAwareBackupDir() { return haBackupDir != null ? haBackupDir : backupDir; } public File getLogDir() { return logDir; } public File getBackupDir() { return backupDir; } public File getTempWorkDir() { return tempWorkDir; } /** * @return temp directory for support content */ public File getSupportDir() { return supportDir; } public File getTempUploadDir() { return tempUploadDir; } public File getPluginsDir() { return pluginsDir; } public File getLogoDir() { return logoDir; } public File getOrCreateSubDir(String subDirName) throws IOException { return getOrCreateSubDir(getHomeDir(), subDirName); } /** * @return {@code true} if {@link #ARTIFACTORY_HA_NODE_PROPERTIES_FILE} and {@link #CLUSTER_PROPS_FILE} exists */ public boolean isHaConfigured() { return HaNodeProperties != null && clusterProperties != null; } /** * @return the {@link HaNodeProperties} object that represents the * {@link #ARTIFACTORY_HA_NODE_PROPERTIES_FILE} contents, or null if HA was not configured properly */ @Nullable public HaNodeProperties getHaNodeProperties() { return HaNodeProperties; } @Nullable public ClusterProperties getClusterProperties() { return clusterProperties; } private File getOrCreateSubDir(File parent, String subDirName) throws IOException { File subDir = new File(parent, subDirName); FileUtils.forceMkdir(subDir); return subDir; } private void create() { try { // Create or find all the needed sub folders etcDir = getOrCreateSubDir("etc"); dataDir = getOrCreateSubDir("data"); logDir = getOrCreateSubDir("logs"); backupDir = getOrCreateSubDir("backup"); supportDir = getOrCreateSubDir("support"); File tempRootDir = getOrCreateSubDir(dataDir, "tmp"); tempWorkDir = getOrCreateSubDir(tempRootDir, "work"); tempUploadDir = getOrCreateSubDir(tempRootDir, "artifactory-uploads"); //Manage the artifactory.system.properties file under etc dir initAndLoadSystemPropertyFile(); //Check the write access to all directories that need it checkWritableDirectory(dataDir); checkWritableDirectory(logDir); checkWritableDirectory(backupDir); checkWritableDirectory(supportDir); checkWritableDirectory(tempRootDir); checkWritableDirectory(tempWorkDir); checkWritableDirectory(tempUploadDir); //If ha props exist, load the storage from cluster_home/ha-etc File haPropertiesFile = getArtifactoryHaPropertiesFile(); if (haPropertiesFile.exists()) { //load ha properties HaNodeProperties = new HaNodeProperties(); HaNodeProperties.load(haPropertiesFile); File haArtifactoryHome = HaNodeProperties.getClusterHome(); if (!haArtifactoryHome.exists()) { throw new RuntimeException( "Artifactory HA home does not exist: " + haArtifactoryHome.getAbsolutePath()); } //create directory structure haEtcDir = getOrCreateSubDir(haArtifactoryHome, "ha-etc"); haDataDir = getOrCreateSubDir(haArtifactoryHome, "ha-data"); haBackupDir = getOrCreateSubDir(haArtifactoryHome, "ha-backup"); checkWritableDirectory(haEtcDir); checkWritableDirectory(haDataDir); checkWritableDirectory(haBackupDir); //load cluster properties File clusterPropertiesFile = getArtifactoryClusterPropertiesFile(); clusterProperties = new ClusterProperties(); clusterProperties.load(clusterPropertiesFile); } pluginsDir = getOrCreateSubDir(getHaAwareEtcDir(), "plugins"); logoDir = getOrCreateSubDir(getHaAwareEtcDir(), "ui"); checkWritableDirectory(pluginsDir); try { //noinspection ConstantConditions for (File rootTmpDirChild : tempRootDir.listFiles()) { if (rootTmpDirChild.isDirectory()) { FileUtils.cleanDirectory(rootTmpDirChild); } else { FileUtils.deleteQuietly(rootTmpDirChild); } } } catch (Exception e) { System.out.println(ArtifactoryHome.class.getName() + " - Warning: unable to clean temporary directories. Cause: " + e.getMessage()); } } catch (Exception e) { throw new IllegalArgumentException( "Could not initialize artifactory home directory due to: " + e.getMessage(), e); } } private String findArtifactoryHome(SimpleLog logger) { String home = System.getProperty(SYS_PROP); String artHomeSource = "System property"; if (home == null) { //Try the environment var home = System.getenv(ENV_VAR); artHomeSource = "Environment variable"; if (home == null) { home = new File(System.getProperty("user.home", "."), ".artifactory").getAbsolutePath(); artHomeSource = "Default (user home)"; } } home = home.replace('\\', '/'); logger.log("Using artifactory.home at '" + home + "' resolved from: " + artHomeSource); return home; } /** * Checks the existence of the logback configuration file under the etc directory. If the file doesn't exist this * method will extract a default one from the war. */ public File getLogbackConfig() { File etcDir = new File(getHomeDir(), "etc"); File logbackFile = new File(etcDir, LOGBACK_CONFIG_FILE_NAME); if (!logbackFile.exists()) { try { //Copy from default URL configUrl = ArtifactoryHome.class.getResource("/META-INF/default/" + LOGBACK_CONFIG_FILE_NAME); FileUtils.copyURLToFile(configUrl, logbackFile); } catch (IOException e) { // we don't have the logger configuration - use System.err System.err.printf("Could not create default %s into %s\n", LOGBACK_CONFIG_FILE_NAME, logbackFile); e.printStackTrace(); } } return logbackFile; } /** * Returns the content of the artifactory.config.import.xml file * * @return Content of artifactory.config.import.xml if exists, null if not */ public String getImportConfigXml() { File importConfigFile = getArtifactoryConfigImportFile(); if (importConfigFile.exists()) { try { String configContent = FileUtils.readFileToString(importConfigFile, "utf-8"); if (StringUtils.isNotBlank(configContent)) { File bootstrapConfigFile = getArtifactoryConfigBootstrapFile(); org.artifactory.util.Files.switchFiles(importConfigFile, bootstrapConfigFile); return configContent; } } catch (IOException e) { throw new RuntimeException("Could not read data from '" + importConfigFile.getAbsolutePath() + "' file due to: " + e.getMessage(), e); } } return null; } public String getBootstrapConfigXml() { File oldLocalConfig = getArtifactoryConfigFile(); File newBootstrapConfig = getArtifactoryConfigBootstrapFile(); String result; if (newBootstrapConfig.exists()) { try { result = FileUtils.readFileToString(newBootstrapConfig, "utf-8"); } catch (IOException e) { throw new RuntimeException("Could not read data from '" + newBootstrapConfig.getAbsolutePath() + "' file due to: " + e.getMessage(), e); } } else if (oldLocalConfig.exists()) { try { result = FileUtils.readFileToString(oldLocalConfig, "utf-8"); } catch (IOException e) { throw new RuntimeException("Could not read data from '" + newBootstrapConfig.getAbsolutePath() + "' file due to: " + e.getMessage(), e); } } else { String resPath = "/META-INF/default/" + ARTIFACTORY_CONFIG_FILE; InputStream is = ArtifactoryHome.class.getResourceAsStream(resPath); if (is == null) { throw new RuntimeException("Could read the default configuration from classpath at " + resPath); } try { result = IOUtils.toString(is, "utf-8"); } catch (IOException e) { throw new RuntimeException( "Could not read data from '" + resPath + "' file due to: " + e.getMessage(), e); } } return result; } public void renameInitialConfigFileIfExists() { File initialConfigFile = getArtifactoryConfigFile(); if (initialConfigFile.isFile()) { org.artifactory.util.Files.switchFiles(initialConfigFile, getArtifactoryConfigBootstrapFile()); } } public ArtifactorySystemProperties getArtifactoryProperties() { return artifactorySystemProperties; } public MimeTypes getMimeTypes() { return mimeTypes; } public File getHomeArtifactoryPropertiesFile() { return new File(dataDir, ARTIFACTORY_PROPERTIES_FILE); } public File getHaArtifactoryPropertiesFile() { return new File(haDataDir, ARTIFACTORY_PROPERTIES_FILE); } private URL getDefaultArtifactoryPropertiesUrl() { return ArtifactoryHome.class.getResource("/META-INF/" + ARTIFACTORY_PROPERTIES_FILE); } public void writeBundledHomeArtifactoryProperties() { File artifactoryPropertiesFile = getHomeArtifactoryPropertiesFile(); //Copy the artifactory.properties file into the data folder try { //Copy from default FileUtils.copyURLToFile(getDefaultArtifactoryPropertiesUrl(), artifactoryPropertiesFile); } catch (IOException e) { throw new RuntimeException("Could not copy " + ARTIFACTORY_PROPERTIES_FILE + " to " + artifactoryPropertiesFile.getAbsolutePath(), e); } } public void writeBundledHaArtifactoryProperties() { File artifactoryHaPropertiesFile = getHaArtifactoryPropertiesFile(); //Copy the artifactory.properties file into the data folder try { //Copy from default FileUtils.copyURLToFile(getDefaultArtifactoryPropertiesUrl(), artifactoryHaPropertiesFile); } catch (IOException e) { throw new RuntimeException("Could not copy " + ARTIFACTORY_PROPERTIES_FILE + " to " + artifactoryHaPropertiesFile.getAbsolutePath(), e); } } public CompoundVersionDetails readRunningArtifactoryVersion() { try (InputStream inputStream = ArtifactoryHome.class .getResourceAsStream("/META-INF/" + ARTIFACTORY_PROPERTIES_FILE)) { CompoundVersionDetails details = ArtifactoryVersionReader.read(inputStream); //Sanity check if (!details.isCurrent()) { throw new IllegalStateException("Running version is not the current version. " + "Running: " + details + " Current: " + details.getVersion()); } return details; } catch (IOException e) { throw new RuntimeException( "Unexpected exception occurred: Fail to load artifactory.properties from class resource", e); } } /** * Copy the system properties file and set its data as system properties */ public void initAndLoadSystemPropertyFile() { // Expose the properties inside artifactory.system.properties File systemPropertiesFile = getArtifactorySystemPropertiesFile(); if (!systemPropertiesFile.exists()) { try { //Copy from default URL url = ArtifactoryHome.class .getResource("/META-INF/default/" + ARTIFACTORY_SYSTEM_PROPERTIES_FILE); if (url == null) { throw new RuntimeException("Could not read classpath resource '/META-INF/default/" + ARTIFACTORY_SYSTEM_PROPERTIES_FILE + "'. Make sure Artifactory home is readable by the current user."); } FileUtils.copyURLToFile(url, systemPropertiesFile); } catch (IOException e) { throw new RuntimeException("Could not create the default '" + ARTIFACTORY_SYSTEM_PROPERTIES_FILE + "' at '" + systemPropertiesFile.getAbsolutePath() + "'.", e); } } artifactorySystemProperties = new ArtifactorySystemProperties(); artifactorySystemProperties.loadArtifactorySystemProperties(systemPropertiesFile, getHomeArtifactoryPropertiesFile()); } public File getArtifactorySystemPropertiesFile() { return new File(getHaAwareEtcDir(), ARTIFACTORY_SYSTEM_PROPERTIES_FILE); } public File getArtifactoryHaPropertiesFile() { return new File(etcDir, ARTIFACTORY_HA_NODE_PROPERTIES_FILE); } public File getArtifactoryClusterPropertiesFile() { return new File(haEtcDir, CLUSTER_PROPS_FILE); } public void initAndLoadMimeTypes() { File mimeTypesFile = getHaAwareMimeTypesFile(); if (!mimeTypesFile.exists()) { // Copy default mime types configuration file try { URL configUrl = ArtifactoryHome.class .getResource("/META-INF/default/" + ArtifactoryHome.MIME_TYPES_FILE_NAME); FileUtils.copyURLToFile(configUrl, mimeTypesFile); } catch (Exception e) { throw new IllegalStateException("Couldn't start Artifactory. " + "Failed to copy default mime types file: " + mimeTypesFile.getAbsolutePath(), e); } } try { String mimeTypesXml = Files.toString(mimeTypesFile, Charsets.UTF_8); mimeTypes = new MimeTypesReader().read(mimeTypesXml); } catch (Exception e) { throw new RuntimeException("Failed to parse mime types file from: " + mimeTypesFile.getAbsolutePath(), e); } } public File getMimeTypesFile() { return new File(getEtcDir(), MIME_TYPES_FILE_NAME); } public File getHaAwareMimeTypesFile() { return new File(getHaAwareEtcDir(), MIME_TYPES_FILE_NAME); } public File getStoragePropertiesFile() { return new File(getHaAwareEtcDir(), STORAGE_PROPS_FILE_NAME); } public File getMissionControlPropertiesFile() { return new File(getHaAwareEtcDir(), MISSION_CONTROL_FILE_NAME); } public File getArtifactoryConfigFile() { return new File(getHaAwareEtcDir(), ARTIFACTORY_CONFIG_FILE); } public File getArtifactoryConfigLatestFile() { return new File(getHaAwareEtcDir(), ARTIFACTORY_CONFIG_LATEST_FILE); } public File getArtifactoryConfigImportFile() { return new File(getHaAwareEtcDir(), ARTIFACTORY_CONFIG_IMPORT_FILE); } public File getArtifactoryConfigBootstrapFile() { return new File(getHaAwareEtcDir(), ARTIFACTORY_CONFIG_BOOTSTRAP_FILE); } public File getArtifactoryConfigNewBootstrapFile() { return new File(getHaAwareEtcDir(), "new_" + ArtifactoryHome.ARTIFACTORY_CONFIG_BOOTSTRAP_FILE); } /** * Missing Closure ;-) */ public interface SimpleLog { public void log(String message); } }