Java tutorial
/* * Copyright 2013 Matt Sicker and Contributors * * 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 atg.tools.dynunit.nucleus; import atg.applauncher.AppLauncher; import atg.applauncher.AppLauncherException; import atg.applauncher.AppModuleManager; import atg.applauncher.MultiInstallLocalAppModuleManager; import atg.applauncher.dynamo.DynamoServerLauncher; import atg.core.util.CommandProcessor; import atg.core.util.JarUtils; import atg.nucleus.DynamoEnv; import atg.nucleus.GenericContext; import atg.nucleus.GenericService; import atg.nucleus.InitialService; import atg.nucleus.Nucleus; import atg.nucleus.PropertyEditors; import atg.nucleus.ServiceException; import atg.nucleus.naming.ComponentName; import atg.nucleus.servlet.NucleusServlet; import atg.service.dynamo.ServerConfig; import atg.tools.dynunit.DynUnit; import atg.tools.dynunit.test.util.FileUtil; import atg.tools.dynunit.util.ComponentUtil; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; import javax.servlet.ServletException; import java.beans.ConstructorProperties; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static atg.tools.dynunit.util.PropertiesUtil.getSystemProperty; import static atg.tools.dynunit.util.PropertiesUtil.setDynamoProperty; import static atg.tools.dynunit.util.PropertiesUtil.setDynamoPropertyIfEmpty; import static atg.tools.dynunit.util.PropertiesUtil.setSystemProperty; import static atg.tools.dynunit.util.PropertiesUtil.setSystemPropertyIfEmpty; import static org.apache.commons.io.FileUtils.toFile; import static org.apache.commons.lang3.Validate.notEmpty; import static org.apache.commons.lang3.Validate.notNull; // TODO: factor out configPath methods to its own class // TODO: migrate parts to NucleusFactory /** * Utility class for aiding in Nucleus component resolution. * * @author adamb * @author msicker */ @Deprecated public class NucleusUtils { //------------------------------------- public static final String DYNUNIT_TESTCONFIG = "atg.tools.dynunit.testconfig"; private static final Logger logger = LogManager.getLogger(); private static final String EXTRACT_TEMP_JAR_FILE_FOR_PATH = "Extract temp jar file for path "; private static final String DYNUNIT_CONFIG = "dynunit-config-"; private static final String FILE = "file:"; private static final String DYNUNIT_TESTCONFIG_ENV = "DYNUNIT_TESTCONFIG"; /** * A map from Nucleus instance to temporary directory. Used by * startNucleusWithModules. */ private static final ConcurrentMap<Nucleus, File> nucleiConfigPathsCache = new ConcurrentHashMap<Nucleus, File>(); /** * Cache of the config path for a given Class. Used by getConfigPath. */ private static final ConcurrentMap<Class, Map<String, File>> configPath = new ConcurrentHashMap<Class, Map<String, File>>(); /** * Creates an Initial.properties file * * @param rootConfigPath * The root of the config path entry. * @param initialServices * initial services list * * @return the create initial services properties file. * * @throws IOException * if an error occurs */ public static File createInitial(File rootConfigPath, Iterable<String> initialServices) throws IOException { Properties prop = new Properties(); prop.setProperty("initialServices", StringUtils.join(initialServices, ',')); return ComponentUtil.newComponent(rootConfigPath, "Initial", InitialService.class, prop); } /** * @see atg.tools.dynunit.util.ComponentUtil#newComponent(java.io.File, String, String, java.util.Properties) */ @Deprecated public static File createProperties(String componentName, @Nullable File configDir, String className, Properties properties) throws IOException { return ComponentUtil.newComponent(configDir, componentName, className, properties); } /** * Allows the absoluteName of the given service to be explicitly defined. * Normally this is determined by the object's location in the Nucleus * hierarchy. For test items that are not really bound to Nucleus, it's * convenient to just give it an absolute name rather than going through * the whole configuration and binding process. * * @param absoluteName * The absolute name value to set * @param service * The service whose absolute name should be set. */ public static void setAbsoluteName(String absoluteName, GenericService service) throws IllegalAccessException { FieldUtils.writeDeclaredField(service, "mAbsoluteName", absoluteName, true); } /** * Adds the given object, component to Nucleus, nucleus at the path given * by componentPath. * * @param nucleus * The Nucleus instance to which the component should be added * @param componentPath * the component path at which the component should be added * @param component * the component instance to add */ public static void addComponent(Nucleus nucleus, String componentPath, Object component) { // make sure it's not already there if (nucleus.resolveName(componentPath) != null) { return; } ComponentName name = ComponentName.getComponentName(componentPath); ComponentName[] subNames = name.getSubNames(); GenericContext[] contexts = new GenericContext[subNames.length - 1]; contexts[0] = nucleus; for (int i = 1; i < subNames.length - 1; i++) { contexts[i] = new GenericContext(); // Make sure it's not there GenericContext tmpContext = (GenericContext) contexts[i - 1].getElement(subNames[i].getName()); if (tmpContext == null) { contexts[i - 1].putElement(subNames[i].getName(), contexts[i]); } else { contexts[i] = tmpContext; } } contexts[contexts.length - 1].putElement(subNames[subNames.length - 1].getName(), component); } /** * Starts Nucleus using the given config directory * * @param configPath * the config path directory entry * to use as the entire config path. * * @return the started Nucleus */ public static Nucleus startNucleus(File configPath) { return startNucleus(configPath.getAbsolutePath()); } /** * Starts Nucleus using the given config directory * * @param configPath * the path name of the config path * entry to specify. * * @return The started nucleus. */ public static Nucleus startNucleus(String configPath) { setSystemPropertyIfEmpty("atg.dynamo.license.read", "true"); setSystemPropertyIfEmpty("atg.license.read", "true"); NucleusServlet.addNamingFactoriesAndProtocolHandlers(); return Nucleus.startNucleus(new String[] { configPath }); } /** * A convenience method for returning the configpath for a test. * baseConfigDirectory is the top level name to be used for the configpath. * Returns a file in the "config/data" subdirectory of the passed in file. * * @param baseConfigDirectory * the base configuration directory. * * @return The calculated configuration path. */ public static File getConfigPath(String baseConfigDirectory) { return getConfigPath(NucleusUtils.class, baseConfigDirectory, true); } /** * A convenience method for returning the configpath for a test. * pConfigDirectory is the top level name to be used for the configpath. * Returns a file in the baseConfigDirectory (or baseConfigDirectory + * "data") subdirectory of the the passed in class's location.<P> * <p/> * The directory location is calculated as (in psuedo-code): * <code> * (classRelativeTo's package location) + "/" + (pConfigDirectory or "data") + "/config" * </code> * * @param classRelativeTo * the class whose package the config/data * (or baseConfigDirectory/data) should be relative in. * @param baseConfigDirectory * the base configuration directory If null, * uses "config". * @param createDirectory * whether to create the config/data subdirectory if * it does not exist. * * @return The calculated configuration path. */ public static File getConfigPath(Class classRelativeTo, String baseConfigDirectory, boolean createDirectory) { Map<String, File> baseConfigToFile = configPath.get(classRelativeTo); if (baseConfigToFile == null) { baseConfigToFile = new ConcurrentHashMap<String, File>(); configPath.put(classRelativeTo, baseConfigToFile); } File fileFound = baseConfigToFile.get(baseConfigDirectory); if (!baseConfigToFile.containsKey(baseConfigDirectory)) { String configdirname = "config"; String packageName = StringUtils.replaceChars(classRelativeTo.getPackage().getName(), '.', '/'); if (baseConfigDirectory != null) { configdirname = baseConfigDirectory; } String configFolder = packageName + "/data/" + configdirname; URL dataURL = classRelativeTo.getClassLoader().getResource(configFolder); // Mkdir if (dataURL == null) { URL root = classRelativeTo.getClassLoader().getResource(packageName); File f = null; if (root != null) { f = new File(root.getFile()); } File f2 = new File(f, "/data/" + configdirname); if (createDirectory) { f2.mkdirs(); } dataURL = NucleusUtils.class.getClassLoader().getResource(configFolder); if (dataURL == null) { System.err.println("Warning: Could not find resource \"" + configFolder + "\" in CLASSPATH"); } } if (dataURL != null) {// check if this URL is contained within a jar file // if so, extract to a temp dir, otherwise just return // the directory fileFound = extractJarDataURL(dataURL); baseConfigToFile.put(baseConfigDirectory, fileFound); } } if (fileFound != null) { System.setProperty("atg.configpath", fileFound.getAbsolutePath()); } return fileFound; } /** * This method is used to extract a configdir from a jar archive. * Given a URL this method will extract the jar contents to a temp dir and return that path. * It also adds a shutdown hook to cleanup the tmp dir on normal jvm completion. * If the given URL does not appear to be a path into a jar archive, this method returns * a new File object initialized with <code>dataURL.getFile()</code>. * * @return A temporary directory to be used as a configdir */ private static File extractJarDataURL(URL dataURL) { // TODO: Extract to a temp location // atg.core.util.JarUtils.extractEntry(arg0, arg1, arg2) int endIndex = dataURL.getFile().lastIndexOf('!'); if (endIndex == -1) { // Not a jar file url return new File(dataURL.getFile()); } logger.info(EXTRACT_TEMP_JAR_FILE_FOR_PATH + dataURL.getFile()); File configDir = null; try { final File tempFile = FileUtil.newTempFile(); final File tmpDir = new File(tempFile.getParentFile(), DYNUNIT_CONFIG + System.currentTimeMillis()); String jarPath = dataURL.getFile().substring(0, endIndex); // Strip leading file: int fileColonIndex = jarPath.indexOf(FILE) + FILE.length(); jarPath = jarPath.substring(fileColonIndex, jarPath.length()); JarUtils.unJar(new File(jarPath), tmpDir, false); // Now get the configpath dir relative to this temp dir String relativePath = dataURL.getFile().substring(endIndex + 1, dataURL.getFile().length()); FileUtils.forceDeleteOnExit(tmpDir); configDir = new File(tmpDir, relativePath); } catch (IOException e) { logger.catching(e); } return configDir; } /** * A convenience method for returning the configpath for a test. * pConfigDirectory is the top level name to be used for the configpath. * Returns a file in the "data" subdirectory of the passed in file. * * @param baseConfigDirectory * the base configuration directory. * @param createDirectory * whether to create the config/data subdirectory if * it does not exist. * * @return The calculated configuration path. */ public static File getConfigPath(String baseConfigDirectory, boolean createDirectory) { return getConfigPath(NucleusUtils.class, baseConfigDirectory, createDirectory); } /** * A convenience method for returning the configpath for a test. * pConfigDirectory is the top level name to be used for the configpath. * Returns a file in the baseConfigDirectory (or baseConfigDirectory + * "data") subdirectory of the the passed in class's location. * <p/> * The directory location is calculated as (in pseudo-code): <code> * (classRelativeTo's package location) + "/" + (pConfigDirectory or "data") + "/config" * </code> * This method always creates the config/data subdirectory if it does not * exist. * * @param classRelativeTo * the class whose package the config/data (or * baseConfigDirectory/data) should be relative in. * @param baseConfigDirectory * the base configuration directory If null, uses "config". * * @return The calculated configuration path. */ public static File getConfigPath(Class classRelativeTo, String baseConfigDirectory) { return getConfigPath(classRelativeTo, baseConfigDirectory, true); } public static String getGlobalTestConfig() { String config = getSystemProperty(DYNUNIT_TESTCONFIG); if (config == null) { config = System.getenv(DYNUNIT_TESTCONFIG_ENV); } // If that's null, there is no global test config specified return config; } public static Nucleus startNucleusWithModules(String[] modules, Class classRelativeTo, String initialService) throws ServletException, FileNotFoundException { return startNucleusWithModules( new NucleusStartupOptions(modules, classRelativeTo, classRelativeTo.getSimpleName() + "/config", // FIXME: factor into private method initialService)); } private static File getExistingFile(final String name) throws FileNotFoundException { notEmpty(name); final File file = new File(name); if (file.exists()) { return file; } throw new FileNotFoundException(name); } public static Nucleus startNucleusWithModules(NucleusStartupOptions startupOptions) throws ServletException, FileNotFoundException { notNull(startupOptions); notEmpty(startupOptions.getInitialService()); final File dynamoRoot = getExistingFile(findDynamoRoot()); setDynamoPropertyIfEmpty("atg.dynamo.root", dynamoRoot.getAbsolutePath()); final File dynamoHome = new File(dynamoRoot, "home"); setDynamoPropertyIfEmpty("atg.dynamo.home", dynamoHome.getAbsolutePath()); final String modulesPath = StringUtils.join(startupOptions.getModules(), File.pathSeparatorChar); setDynamoProperty("atg.dynamo.modules", modulesPath); setSystemPropertyIfEmpty("atg.dynamo.license.read", "true"); setSystemPropertyIfEmpty("atg.license.read", "true"); // our temporary server directory. File fileServerDir = null; try { AppModuleManager moduleManager = new MultiInstallLocalAppModuleManager(dynamoRoot.getAbsolutePath(), dynamoRoot, modulesPath); AppLauncher launcher = AppLauncher.getLauncher(moduleManager, modulesPath); // Start Nucleus String configpath = DynamoServerLauncher.calculateConfigPath(launcher, startupOptions.getLiveConfig(), startupOptions.getLayersAsString(), false, null); // use the NucleusUtils config dir as a base, since it // empties out license checks, etc. File fileBaseConfig = getConfigPath(NucleusUtils.class, null, false); if ((fileBaseConfig != null) && fileBaseConfig.exists()) { configpath = configpath + File.pathSeparator + fileBaseConfig.getAbsolutePath(); } // add the additional config path as the last arg, if needed File fileTestConfig = getConfigPath(startupOptions.getClassRelativeTo(), startupOptions.getBaseConfigDirectory(), false); // now add it to the end of our config path if ((fileTestConfig != null) && fileTestConfig.exists()) { configpath = configpath + File.pathSeparator + fileTestConfig.getAbsolutePath(); } else if (fileTestConfig != null) { logger.error("Warning: did not find directory {}", fileTestConfig.getAbsolutePath()); } String dynUnitHome = DynUnit.getHome(); if (dynUnitHome != null) { configpath = configpath + File.pathSeparator + dynUnitHome + File.separatorChar + "licenseconfig"; } // finally, create a server dir. fileServerDir = createTempServerDir(); setSystemProperty("atg.dynamo.server.home", fileServerDir.getAbsolutePath()); NucleusServlet.addNamingFactoriesAndProtocolHandlers(); ArrayList<String> listArgs = new ArrayList<String>(); listArgs.add(configpath); listArgs.add("-initialService"); listArgs.add(startupOptions.getInitialService()); PropertyEditors.registerEditors(); logger.info("Starting nucleus with arguments: " + listArgs); Nucleus n = Nucleus.startNucleus(listArgs.toArray(new String[listArgs.size()])); // remember our temporary server directory for later deletion nucleiConfigPathsCache.put(n, fileServerDir); // clear out the variable, so our finally clause knows not to // delete it fileServerDir = null; return n; } catch (AppLauncherException e) { throw logger.throwing(new ServletException(e)); } catch (IOException e) { throw logger.throwing(new ServletException(e)); } finally { if (fileServerDir != null) { try { // a non-null value means it was created, but not added to our list, // so we should nuke it. FileUtils.deleteDirectory(fileServerDir); } catch (IOException e) { logger.catching(Level.ERROR, e); } } } } /** * A crazily ugly and elaborate method where we try to discover * DYNAMO_ROOT by various means. This is mostly made complicated * by the ROAD DUST environment being so different from devtools. */ private static String findDynamoRoot() { // now let's try to find dynamo home... String dynamoRootStr = DynamoEnv.getProperty("atg.dynamo.root"); if (dynamoRootStr == null) { // let's try to look at an environment variable, just to // see.... dynamoRootStr = CommandProcessor.getProcEnvironmentVar("DYNAMO_ROOT"); } if (dynamoRootStr == null) { // try dynamo home String dynamoHomeStr = DynamoEnv.getProperty("atg.dynamo.home"); if (StringUtils.isEmpty(dynamoHomeStr)) { dynamoHomeStr = null; } if (dynamoHomeStr == null) { dynamoHomeStr = CommandProcessor.getProcEnvironmentVar("DYNAMO_HOME"); if (StringUtils.isEmpty(dynamoHomeStr)) { dynamoHomeStr = null; } if (dynamoHomeStr != null) { // make sure home is set as a property DynamoEnv.setProperty("atg.dynamo.home", dynamoHomeStr); } } if (dynamoHomeStr != null) { dynamoRootStr = dynamoHomeStr.trim() + File.separator + ".."; } } if (dynamoRootStr == null) { // okay, start searching upwards for something that looks like // a dynamo directory, which should be the case for devtools File currentDir = new File(new File(".").getAbsolutePath()); String strDynamoHomeLocalConfig = "Dynamo" + File.separator + "home" + File.separator + "localconfig"; while (currentDir != null) { File filePotentialHomeLocalconfigDir = new File(currentDir, strDynamoHomeLocalConfig); if (filePotentialHomeLocalconfigDir.exists()) { dynamoRootStr = new File(currentDir, "Dynamo").getAbsolutePath(); logger.debug("Found dynamo root via parent directory: " + dynamoRootStr); break; } currentDir = currentDir.getParentFile(); } } if (dynamoRootStr == null) { // okay, we are not devtools-ish, so let's try using our ClassLoader // to figure things out. URL urlClass = NucleusUtils.class.getClassLoader().getResource("atg/nucleus/Nucleus.class"); // okay... this should be jar URL... if ((urlClass != null) && "jar".equals(urlClass.getProtocol())) { String strFile = urlClass.getFile(); int separator = strFile.indexOf('!'); strFile = strFile.substring(0, separator); File fileCur = null; try { fileCur = urlToFile(new URL(strFile)); } catch (MalformedURLException e) { // ignore } if (fileCur != null) { String strSubPath = "DAS/taglib/dspjspTaglib/1.0".replace('/', File.separatorChar); while ((fileCur != null) && fileCur.exists()) { if (new File(fileCur, strSubPath).exists()) { dynamoRootStr = fileCur.getAbsolutePath(); logger.debug("Found dynamo root by Nucleus.class location: " + dynamoRootStr); break; } fileCur = fileCur.getParentFile(); } } } } return dynamoRootStr; } @Deprecated private static File urlToFile(URL url) { return toFile(url); } /** * Create a temporary, empty server directory. This is to satisfy * Dynamo's need to have a server directory, yet not conflict if * multiple tests are running at the same time against the same Dynamo * instance. The directory name is generated by File.createTempFile. * * @return the created temporary server directory. * * @throws IOException * if an error occurs */ private static File createTempServerDir() throws IOException { File fileTemp = File.createTempFile("tempServer", "dir"); fileTemp.delete(); if (!fileTemp.mkdir()) { throw new IOException("Unable to create directory " + fileTemp.getAbsolutePath()); } for (String strSubDir : ServerConfig.smConfigFileDirs) { File fileSubDir = new File(fileTemp, strSubDir); if (!fileSubDir.mkdirs()) { throw new IOException("Unable to create directory " + fileSubDir.getAbsolutePath()); } } return fileTemp; } /** * This method starts nucleus with a config path calculated from the * specified list of Dynamo modules ("DAS", "DPS", "DSS", * "Publishing.base", etc). Additionally adds a directory calculated relative * to the location of classRelativeTo's package name from the classloader. * The added config directory is calculated as (in pseudo-code): * <code> * (classRelativeTo's package location) + "/data/" + (baseConfigDirectory or "config") * </code> * and is only added if the directory exists. <P> * <p/> * You must specify a <code>initialService</code> parameter, which * will be the initial service started by Nucleus (rather than the * normally Initial component, which would do a full Nucleus component * start-up). <P> * <p/> * This method also creates a temporary server directory, which is deleted * when stopNucleus in invoked on the returned directory. <P> * <p/> * Note: If you need to start up a complete ATG instance, you should * use DUST rather than a unit test. <P> * <p/> * Note: You may also wish to use a {@see * atg.nucleus.ConfigCreationFilter}. You can either set a value for * Nucleus.CREATION_FILTER_CLASS_PROPERTY_NAME * ("atg.nucleus.Nucleus.creationFilterClass") as a DynamoEnv or System * property, or set the creationFilter property in Nucleus.properties in * your configuration. This allows on to block creation of referenced * components without having to make additional properties file changes. * <p/> * Note 3: Nucleus's classReplacementMap can also be useful for replacing * a component instance with a subclass. * * @param modules * the list of modules to use to calculate the * Nucleus configuration path. * @param classRelativeTo * the class whose package the config/data * (or baseConfigDirectory/data) should be relative in. * @param baseConfigDirectory * the base configuration directory. If * this parameter is non-null, the relative configuration * subdirectory * will be * ("data/" + baseConfigDirectory) rather than "data/config". * @param initialService * the nucleus path of the Nucleus component * to start-up. This is a required property to prevent accidental * full start-up. * * @return the started Nucleus instance that should later be shut down * with the stopNucleus method. * * @throws ServletException * if an error occurs */ public static Nucleus startNucleusWithModules(String[] modules, Class classRelativeTo, String baseConfigDirectory, String initialService) throws ServletException, FileNotFoundException { return startNucleusWithModules( new NucleusStartupOptions(modules, classRelativeTo, baseConfigDirectory, initialService)); } /** * Shutdown the specified Nucleus and try to delete the associated * temporary server directory. Typically used on a Nucleus created * by startNucleusWithModules. * * @param nucleus * the nucleus instance to shut down. * * @throws ServiceException * if an error occurs * @throws IOException * if an error occurs (such as a failure * to remove the temporary server directory). */ public static void stopNucleus(Nucleus nucleus) throws IOException, ServiceException { if (nucleus.isRunning()) { try { nucleus.stopService(); } catch (ServiceException e) { throw logger.throwing(e); } finally { cleanUpNucleusTemporaryFiles(nucleus); } } } private static void cleanUpNucleusTemporaryFiles(final Nucleus nucleus) throws IOException { final File temporaryFilesDirectory = nucleiConfigPathsCache.get(nucleus); if (temporaryFilesDirectory == null) { return; } try { FileUtils.deleteDirectory(temporaryFilesDirectory); } finally { nucleiConfigPathsCache.remove(nucleus); } } /** * This method returns a free port number on the current machine. There is * some chance that the port number could be taken by the time the caller * actually gets around to using it. * <p/> * This method returns -9999 if it's not able to find a port. */ public static int findFreePort() { ServerSocket socket = null; int freePort = -9999; try { socket = new ServerSocket(0); freePort = socket.getLocalPort(); } catch (IOException e) { logger.catching(e); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { logger.catching(e); } } return freePort; } /** * A class representing NucleusStartupOptions, used by * startNucleusWithModules(). */ public static class NucleusStartupOptions { /** * List of dynamo modules. */ private final String[] modules; /** * Class whose package data subdir is relative to. */ private final Class<?> classRelativeTo; /** * The base config directory, relative to classRelativeTo's package * + "/data". If null, then "config" */ private final String baseConfigDirectory; /** * The Nucleus path of the initial service to resolve. */ private final String initialService; private String[] layers; private boolean liveConfig; /** * This constructor creates NucleusStartupOptions with the * specified list of Dynamo modules ("DAS", "DPS", "DSS", * "Publishing.base", etc). * Additionally sets opts to add a directory calculated relative * to the location of classRelativeTo's package name from the classloader. * The added config directory is calculated as (in psuedocode): * <code> * (classRelativeTo's package location) + "/data/" + (classRelativeTo's simpleClassName) * + * "/config" * </code> * and is only added if the directory exists. <P> * <p/> * You must specify a <code>initialService</code> parameter, which * will be the initial service started by Nucleus (rather than the * normally Initial component, which would do a full Nucleus component * start-up). <P> * * @param modules * the list of modules to use to calculate the * Nucleus configuration path. * @param classRelativeTo * the class whose name and package * will be used for the {packageName}/config/{simpleClassName}/data * directory * @param initialService * the nucleus path of the Nucleus component * to start-up. This is a required property to prevent accidental * full start-up. */ @ConstructorProperties({ "modules", "classRelativeTo", "initialServices" }) public NucleusStartupOptions(String[] modules, Class<?> classRelativeTo, String initialService) { this.modules = modules; this.classRelativeTo = classRelativeTo; this.initialService = initialService; baseConfigDirectory = classRelativeTo.getSimpleName() + File.separatorChar + "config"; } /** * This constructor creates NucleusStartupOptions with the * specified list of Dynamo modules ("DAS", "DPS", "DSS", * "Publishing.base", etc). * Additionally sets opts to add a directory calculated relative * to the location of classRelativeTo's package name from the classloader. * The added config directory is calculated as (in pseudo-code): * <code> * (classRelativeTo's package location) + "/" + (pConfigDirectory or "data") + "/config" * </code> * and is only added if the directory exists. <P> * <p/> * You must specify a <code>initialService</code> parameter, which * will be the initial service started by Nucleus (rather than the * normally Initial component, which would do a full Nucleus component * start-up). <P> * * @param modules * the list of modules to use to calculate the * Nucleus configuration path. * @param classRelativeTo * the class whose package the config/data * (or baseConfigDirectory/data) should be relative in. * @param baseConfigDirectory * the base configuration directory. If * this parameter is non-null, the relative configuration * subdirectory will be * ("data/" + baseConfigDirectory) rather than "data/config". * @param initialService * the nucleus path of the Nucleus component * to start-up. This is a required property to prevent * accidental full start-up. */ @ConstructorProperties({ "modules", "classRelativeTo", "baseConfigDirectory", "initialService" }) public NucleusStartupOptions(String[] modules, Class classRelativeTo, String baseConfigDirectory, String initialService) { this.modules = modules; this.classRelativeTo = classRelativeTo; this.initialService = initialService; this.baseConfigDirectory = baseConfigDirectory; } /** * Return the list of modules for starting Nucleus. These modules * are the modules whose config path will be included. */ public String[] getModules() { return modules; } //------------------------------------- // property: baseConfigDirectory /** * Return the "class relative to" property. This is the Class whose * package the config directory will be relative to. */ public Class getClassRelativeTo() { return classRelativeTo; } //------------------------------------- // property: layers /** * Gets the initialService. This is the InitialService for Nucleus * to resolve at start-up. Required. */ public String getInitialService() { return initialService; } /** * Set the basic config directory. This is the directory that will be * tacked on to the package path of the classRelativeTo class. If this * property is non-null, the relative configuration subdirectory will * be ("data/" + baseConfigDirectory). */ public String getBaseConfigDirectory() { return baseConfigDirectory; } /** * Returns the Dynamo layers to run with. */ public String[] getLayers() { return layers; } /** * Sets the Dynamo layers to run with. */ public void setLayers(String[] layers) { this.layers = layers; } //------------------------------------- // property: liveconfig /** * Return the layers as a string appropriate for passing to * DynamoServerLauncher, calculateConfigPath. * * @return null if layers is null. Otherwise returns a space delimited * list of layers. */ public String getLayersAsString() { return StringUtils.join(layers, ' '); } /** * Returns property liveconfig. * * @return true if liveconfig should be set, false otherwise. */ public boolean getLiveConfig() { return liveConfig; } /** * Sets property liveconfig. * * @param liveConfig * true if Nucleus should be started in liveconfig * mode, false otherwise. */ public void setLiveConfig(boolean liveConfig) { this.liveConfig = liveConfig; } /** * Modify Nucleus command-line options, as needed. This will * be invoked just before Nucleus is started as a final * chance to adjust any command-line options. */ public void modifyNucleusCommandLineOptions(List<String> listArgs) { } } }