/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt 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.test.faces; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Enumeration; import java.util.EventListener; import java.util.logging.Level; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import javax.servlet.Filter; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextListener; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; import javax.servlet.jsp.JspFactory; import org.jboss.test.faces.staging.HttpConnection; import org.jboss.test.faces.staging.ServerLogger; import org.jboss.test.faces.staging.StagingServer; /** * @author Nick Belaevski * */ public abstract class ApplicationServer { private static final Logger log = ServerLogger.RESOURCE.getLogger(); public static final String APPLICATION_SERVER_PROPERTY = ApplicationServer.class.getName(); /** * Internal method used by the {@link #addResourcesFromDirectory(String, URL)} to process 'file' protocol. * * @param resource * source directory. * @param baseDirectory * target virtual directory. */ protected void addResourcesFromFile(String resourcePath, URL resource) { File file = new File(resource.getPath()); if (!file.isDirectory()) { file = file.getParentFile(); } try { addFiles(resourcePath, file); } catch (MalformedURLException e) { throw new TestException(e); } } /** * Internal method used by the {@link #addResourcesFromDirectory(String, URL)} to process 'jar' protocol. * * @param resource * URL to the any object in the source directory. * @param baseDirectory * target virtual directory. */ protected void addResourcesFromJar(String resourcePath, URL resource) { try { String jarPath = resource.getPath(); String entry = jarPath.substring(jarPath.indexOf('!') + 2); jarPath = jarPath.substring(0, jarPath.indexOf('!')); File file = new File(new URI(jarPath)); ZipFile zip = new ZipFile(file); Enumeration<? extends ZipEntry> entries = zip.entries(); entry = entry.substring(0, entry.lastIndexOf('/') + 1); while (entries.hasMoreElements()) { ZipEntry zzz = entries.nextElement(); if (zzz.getName().startsWith(entry) && !zzz.isDirectory()) { String relativePath = zzz.getName().substring(entry.length()); URL relativeResource = new URL(resource, relativePath); addResource(resourcePath + "/" + relativePath, relativeResource); } } } catch (IOException e) { throw new TestException("Error read Jar content", e); } catch (URISyntaxException e) { throw new TestException(e); } } /** * Internal reccursive method process directory content and all subdirectories. * * @param baseDirectory * @param file * @throws MalformedURLException */ protected void addFiles(String resourcePath, File file) throws MalformedURLException { File[] files = file.listFiles(); for (File subfile : files) { if (!subfile.isDirectory()) { addResource(resourcePath + "/" + subfile.getName(), subfile.toURI().toURL()); } else { String directoryPath = resourcePath + "/" + subfile.getName(); addDirectory(directoryPath); addFiles(directoryPath, subfile); } } } protected abstract void addDirectory(String directoryPath); /** * Register servlet in this application server * * @param servletHolder */ public abstract void addServlet(ServletHolder servletHolder); /** * Register filter in this application server * * @param filterHolder */ public abstract void addFilter(FilterHolder filterHolder); /** * Add web application init parameter. * * @param name * @param value */ public abstract void addInitParameter(String name, String value); /** * Add default mime type for serve files with given extension. * * @param extension * @param mimeType */ public abstract void addMimeType(String extension, String mimeType); public abstract void addContent(String path, String content); /** * Add java resource to the virtual web application content. This method makes all parent directories as needed. * * @param path * path to the file in the virtual web server. * @param resource * path to the resource in the classpath, as required by the {@link ClassLoader#getResource(String)}. */ public abstract void addResource(String path, String resource); /** * Add resource to the virtual veb application content. This method makes all parent directories as needed. * * @param path * path to the file in the virtual web server. * @param resource * {@code URL} to the file content. */ public abstract void addResource(String path, URL resource); /** * Add all resources from the directory to the virtual web application content. * * @param path * name of the target directory in the virtual web application. If no such directory exists, it will be * created, as well as all parent directories as needed. * @param resource * {@code URL} to the source directory or any file in the source directory. Only 'file' or 'jar' * protocols are supported. If this parameter points to a file, it will be converted to a enclosing * directory. */ public void addResourcesFromDirectory(String path, URL resource) { String protocol = resource.getProtocol(); if ("jar".equals(protocol)) { addResourcesFromJar(path, resource); } else if ("file".equals(protocol)) { addResourcesFromFile(path, resource); } else { throw new TestException("Unsupported protocol " + protocol); } } /** * Add all files from the directory to the virtual web application content. * * @param path * name of the target directory in the virtual web application. If no such directory exists, it will be * created, as well as all parent directories as needed. * @param resource * {@code File} of the source directory or any file in the source directory. If this parameter points to * a file, it will be converted to a enclosing directory. */ public void addResourcesFromDirectory(String path, File directory) { if (!directory.exists()) { throw new TestException("directory does not exist:" + directory.getAbsolutePath()); } try { addFiles(path, directory); } catch (MalformedURLException e) { throw new TestException(e); } } /** * Add web-application wide listenes, same as it is defined by the <listener> element in the web.xml file for * a real server. Supported listener types: * <ul> * <li>{@link ServletContextListener}</li> * <li>{@link ServletContextAttributeListener}</li> * <li>{@link HttpSessionListener}</li> * <li>{@link HttpSessionAttributeListener}</li> * <li>{@link ServletRequestListener}</li> * <li>{@link ServletRequestAttributeListener}</li> * </ul> * * @param listener * web listener instance. */ public abstract void addWebListener(EventListener listener); /** * Virtual server initialization. This method creates instances of the {@link ServletContext}, {@link JspFactory}, * informs {@link ServletContextListener} ind inits all {@link Filter} and {@link Servlet} instances. It should be * called from test setUp method to prepare testing environment. */ public abstract void init(); /** * Stop wirtual server. This method informs {@link ServletContextListener} ind inits all {@link Filter} and * {@link Servlet} instances, as well remove all internal objects. It should be called from the testt thearDown * method to clean up testing environment. * */ public abstract void destroy(); /** * Get instance of virtual web application context. * * @return context instance. */ public abstract ServletContext getContext(); /** * Get port on which server accepts connections * * @return */ public abstract int getPort(); /** * Get virtual connection to the given URL. Even thought for an http request to the external servers, only local * connection to the virtual server will be created. * * @param url * request url. * @return local connection to the appropriate servlet in the virtual server. * @throws {@link TestException} if no servlet found to process given URL. */ public abstract HttpConnection getConnection(URL url); public abstract boolean isSessionPerThread(); public abstract void setSessionPerThread(boolean sessionPerThread); /** * Get virtual server session object. Create new one if necessary. * * @return instance of the virtual server session. */ public abstract HttpSession getSession(); /** * * Returns the current <code>HttpSession</code> associated with this server or, if there is no current session and * <code>create</code> is true, returns a new session. Staging server supports only one session per instance, * different clients for the same server instance does not supported. * * <p> * If <code>create</code> is <code>false</code> and the request has no valid <code>HttpSession</code>, this method * returns <code>null</code>. * * * @param create * <code>true</code> to create a new session for this request if necessary; <code>false</code> to return * <code>null</code> if there's no current session * * * @return the <code>HttpSession</code> associated with this server instance or <code>null</code> if * <code>create</code> is <code>false</code> and the server has no session * */ public abstract HttpSession getSession(boolean create); /** * Creates implementation of {@link ApplicationServer} according to system property. * If system property is not set, creates default implementation. * * @return server or default */ public static ApplicationServer createApplicationServer() { String applicationServerClassName = System.getProperty(APPLICATION_SERVER_PROPERTY); if (applicationServerClassName != null) { return createApplicationServer(applicationServerClassName); } return new StagingServer(); } /** * <p class="changed_added_4_0"></p> * @param applicationServerClassName * @return */ private static ApplicationServer createApplicationServer(String applicationServerClassName) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if (classLoader == null) { classLoader = ApplicationServer.class.getClassLoader(); } Class<?> applicationServer; try { applicationServer = Class.forName(applicationServerClassName, true, classLoader); Class<? extends ApplicationServer> applicationServerClass = applicationServer.asSubclass(ApplicationServer.class); return applicationServerClass.newInstance(); } catch (Exception e) { log.log(Level.SEVERE, e.getMessage(), e); throw new TestException(e); } } }