/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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 org.civilian.context.test; import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import org.civilian.Application; import org.civilian.Context; import org.civilian.application.ConfigKeys; import org.civilian.content.ContentType; import org.civilian.content.ContentTypeLookup; import org.civilian.context.servlet.ServletUtil; import org.civilian.internal.Logs; import org.civilian.resource.Path; import org.civilian.util.Check; import org.civilian.util.FileType; import org.civilian.util.Iterators; import org.civilian.util.ResourceLoader; import org.civilian.util.Settings; /** * TestContext is a {@link Context} implementation which can be used in a test environment. */ public class TestContext extends Context { public static final HashMap<String,ContentType> EXT_2_CONTENTTYPES = new HashMap<>(); static { EXT_2_CONTENTTYPES.put("html", ContentType.TEXT_HTML); EXT_2_CONTENTTYPES.put("css", ContentType.TEXT_CSS); EXT_2_CONTENTTYPES.put("js", ContentType.APPLICATION_JAVASCRIPT); EXT_2_CONTENTTYPES.put("json", ContentType.APPLICATION_JSON); EXT_2_CONTENTTYPES.put("xml", ContentType.APPLICATION_XML); EXT_2_CONTENTTYPES.put("txt", ContentType.TEXT_PLAIN); } /** * Creates a TestContext for the current directory. */ public TestContext() { this(new File(".")); } /** * Creates a TestContext for the given directory. * The directory should contain all resources of a servlet application, * including a WEB/-INF subdirectory. */ public TestContext(File dir) { directory_ = FileType.EXISTENT_DIR.check(dir); contentTypeLookup_ = ContentTypeLookup.forMap(EXT_2_CONTENTTYPES); resourceLoader_ = ResourceLoader.builder.forDirectory(directory_); } /** * Returns the root directory of the TestContext. */ public File getDirectory() { return directory_; } /** * Sets the develop flag. */ public void setDevelop(boolean develop) { develop_ = develop; } /** * Returns the settings used by the TestContext. * By default the settings are stored in file civilian.ini */ public Settings getSettings() throws IOException { if (settings_ == null) setSettings(DEFAULT_CONFIG_FILE); return settings_; } /** * Sets the settings of the TestContext. */ public void setSettings(Settings settings) { settings_ = Check.notNull(settings, "settings"); } /** * Sets the settings of the TestContext. * @param configName a name of a configuration file */ public void setSettings(String configName) throws IOException { setSettings(readSettings(configName)); } /** * Initializes the context from the settings and adds all applications * specified in the settings to the context. */ public void init() throws Exception { // call the protected implementation init(getAppClassLoader(), getSettings()); } private ClassLoader getAppClassLoader() throws Exception { if (appClassLoader_ == null) appClassLoader_ = createAppClassLoader(); return appClassLoader_; } private ClassLoader createAppClassLoader() throws Exception { ArrayList<URL> urls = new ArrayList<>(); File classesDir = new File(directory_, "WEB-INF/classes"); if (classesDir.exists() && classesDir.isDirectory()) urls.add(classesDir.toURI().toURL()); File libDir = new File(directory_, "WEB-INF/lib"); if (libDir.exists() && libDir.isDirectory()) { File[] files = libDir.listFiles(); if (files != null) { for (File f : files) { if (!f.isDirectory() && f.getName().endsWith(".jar")) urls.add(f.toURI().toURL()); } } } ClassLoader cl = getClass().getClassLoader(); if (urls.size() > 0) cl = new URLClassLoader(urls.toArray(new URL[urls.size()]), cl); return cl; } @Override protected Object connect(Application app, boolean supportAsync) { return null; } @Override protected void disconnect(Application app) { } /** * Returns the ResourceLoader which servers files from * the context directory. */ @Override public ResourceLoader getResourceLoader() { return resourceLoader_; } /** * Sets the ResourceLoader. */ public void setResourceLoader(ResourceLoader resourceLoader) { resourceLoader_ = Check.notNull(resourceLoader, "resourceLoader"); } /** * Returns the real path of a file within the context directory. */ @Override public String getRealPath(String path) { return new File(directory_, path).getAbsolutePath(); } /** * Returns if the path goes into the WEB-INF or META-INF subdirectory. */ @Override public boolean isProhibitedPath(String path) { return ServletUtil.isProhibitedPath(path); } /** * Returns a path within the configF subdirectory. */ @Override public String getConfigPath(String path) { return configPath_ + path; } /** * Returns the config path below the context directory. */ public String getConfigPath() { return configPath_; } /** * Sets the config path (relative to context directory). */ public void setConfigPath(String path) { configPath_ = Check.notNull(path, "path"); } /** * Returns "1.0". */ @Override public String getServerVersion() { return "1.0"; } /** * Returns "TestContext". */ @Override public String getServerInfo() { return "TestContext"; } /** * Returns Path.ROOT. */ @Override public Path getPath() { return Path.ROOT; } /** * Returns a ContentTypeLookup to translate file names into content types. */ @Override public ContentTypeLookup getContentTypeLookup() { return contentTypeLookup_; } //-------------------------- // attributes //-------------------------- @Override public Object getAttribute(String name) { return attributes_ != null ? attributes_.get(name) : null; } @Override public Iterator<String> getAttributeNames() { return attributes_ != null ? attributes_.keySet().iterator() : Iterators.<String>empty(); } @Override public void setAttribute(String name, Object object) { if (attributes_ == null) attributes_ = new HashMap<>(); attributes_.put(name, object); } //-------------------------- // applications //-------------------------- /** * Allows to add an application to the context. The application settings * are taken from civilian.ini * @param app the application * @param id the application id * @param relativePath the relative path of the application within the context */ public boolean addApp(Application app, String id, String relativePath) throws IOException { Settings appSettings = new Settings(getSettings(), ConfigKeys.APP_PREFIX + id + "."); return addApp(app, id, relativePath, appSettings); } /** * Allows to add an application to the context. * @param app the application * @param id the application id * @param relativePath the relative path of the application within the context * @param settings application settings */ @Override public boolean addApp(Application app, String id, String relativePath, Settings settings) { return super.addApp(app, id, relativePath, settings); } //-------------------------- // close //-------------------------- /** * Closes all applications of the context. * @see Application#close() */ @Override public void close() { // call the protected implementation super.close(); } /** * Closes an application and removes it from the context. */ @Override public void close(Application app) { // call the protected implementation super.close(app); } //-------------------------- // misc //-------------------------- @Override public void log(String msg, Throwable throwable) { Logs.CONTEXT.error(msg, throwable); } /** * Returns null. */ @Override public <T> T unwrap(Class<T> implClass) { return null; } private final File directory_; private String configPath_ = "WEB-INF/"; private HashMap<String,Object> attributes_; private ContentTypeLookup contentTypeLookup_; private ResourceLoader resourceLoader_; private ClassLoader appClassLoader_; private Settings settings_; }