// Copyright � 2002-2007 Canoo Engineering AG, Switzerland. package com.canoo.webtest.engine; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; import com.canoo.webtest.ant.WebtestTask; import com.canoo.webtest.boundary.ResetScriptRunner; import com.canoo.webtest.engine.xpath.XPathHelper; import com.canoo.webtest.steps.Step; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.ScriptException; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; /** * Represents context information for a webtest. * * @author unknown * @author Marc Guillemot * @author Paul King */ public class Context { private static final Logger LOG = Logger.getLogger(Context.class); /** * The name identifiying the default {@link WebClientContext} that is the current one at test startup. */ public static final String KEY_DEFAULT_WEBCLIENTCONTEXT = "default"; private int fCurrentStepIndex; private WebtestTask fWebtest; private boolean fPrepared; private Map<String, Object> fContextStore = new HashMap<String, Object>(); private ResetScriptRunner fSavedRunner; private final XPathHelper fXPathHelper = new XPathHelper(); private WebClientContext fCurrentWebClientContext = new WebClientContext(KEY_DEFAULT_WEBCLIENTCONTEXT); private final Map<String, WebClientContext> fWebClientContexts = new HashMap<String, WebClientContext>(); private final AtomicReference<ScriptException> backgroundJSError_ = new AtomicReference<ScriptException>(); public Context(final WebtestTask webtest) { fWebtest = webtest; fWebClientContexts.put(KEY_DEFAULT_WEBCLIENTCONTEXT, fCurrentWebClientContext); } public boolean containsKey(final String key) { return fContextStore.containsKey(key); } public Object get(final String key) { return fContextStore.get(key); } /** * Shortcut method to get the configuration of the * * @return the configuration * @see WebtestTask */ public Configuration getConfig() { return getWebtest().getConfig(); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getCurrentForm */ public HtmlForm getCurrentForm() { return getCurrentWebClientContext().getCurrentForm(); } /** * /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getCurrentHtmlResponse(Step) */ public HtmlPage getCurrentHtmlResponse(final Step step) { return getCurrentWebClientContext().getCurrentHtmlResponse(step); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getCurrentResponse() */ public Page getCurrentResponse() { return getCurrentWebClientContext().getCurrentResponse(); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentResponseFile() * @see WebClientContext#getCurrentResponseFile() */ public String getCurrentResponseFile() { return getCurrentWebClientContext().getCurrentResponseFile(); } public int getCurrentStepNumber() { return fCurrentStepIndex + 1; } /** * Gets the currently active {@link WebClientContext}. * * @return the web client context */ public WebClientContext getCurrentWebClientContext() { return fCurrentWebClientContext; } public int getNumberOfSteps() { return getWebtest().getStepSequence().getSteps().size(); } /** * Gets the currently available {@link WebClientContext} * * @return an unmodifiable Map of (key, {@link WebClientContext}) */ public Map<String, WebClientContext> getWebClientContexts() { return Collections.unmodifiableMap(fWebClientContexts); } /** * Defines the current {@link WebClientContext} creating it if none was previously registered * under this name. * * @param name the name of the {@link WebClientContext} to activate. * The default {@link WebClientContext} is registered under the key {@link #KEY_DEFAULT_WEBCLIENTCONTEXT}. * @return the new current context */ public WebClientContext defineCurrentWebClientContext(final String name) { WebClientContext webClientContext = (WebClientContext) fWebClientContexts.get(name); if (webClientContext == null) { webClientContext = new WebClientContext(name); webClientContext.setWebClient(getConfig().createWebClient()); fWebClientContexts.put(name, webClientContext); LOG.info("Created new WebClientContext for \"" + name + "\""); } fCurrentWebClientContext = webClientContext; return webClientContext; } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getResponses() */ public WebClientContext.StoredResponses getResponses() { return getCurrentWebClientContext().getResponses(); } public ResetScriptRunner getRunner() { return fSavedRunner; } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getSavedPassword() */ public String getSavedPassword() { return getCurrentWebClientContext().getSavedPassword(); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getSavedUserName() */ public String getSavedUserName() { return getCurrentWebClientContext().getSavedUserName(); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#getWebClient() */ public WebClient getWebClient() { return getCurrentWebClientContext().getWebClient(); } /** * Gets the <webtest> for this context. * * @return the task */ public WebtestTask getWebtest() { return fWebtest; } /** * Gets the XPath helper used for this test. It will be responsible to * create the xpath objects with the right custom functions and variables. * * @return the helper */ public XPathHelper getXPathHelper() { return fXPathHelper; } public void increaseStepNumber() { fCurrentStepIndex += 1; } public boolean isPrepared() { return fPrepared; } // generic mechanism to extend context information public void put(final String key, final Object value) { LOG.debug("put(" + key + ", " + value + ")"); fContextStore.put(key, value); } public void remove(final String key) { fContextStore.remove(key); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#restorePreviousResponse() */ public void restorePreviousResponse() { getCurrentWebClientContext().restorePreviousResponse(); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#restoreResponses(com.canoo.webtest.engine.WebClientContext.StoredResponses) */ public void restoreResponses( final WebClientContext.StoredResponses savedResponses) { getCurrentWebClientContext().restoreResponses(savedResponses); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#restoreWindowListener() */ public void restoreWindowListener() { getCurrentWebClientContext().restoreWindowListener(); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#saveResponseAsCurrent(Page) */ public void saveResponseAsCurrent(final Page page) { getCurrentWebClientContext().saveResponseAsCurrent(page); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#setCurrentForm(HtmlForm) */ public void setCurrentForm(final HtmlForm form) { getCurrentWebClientContext().setCurrentForm(form); } public void setPrepared(final boolean prepared) { fPrepared = prepared; } public void setRunner(final ResetScriptRunner sr) { fSavedRunner = sr; } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#setSavedPassword(String) */ public void setSavedPassword(final String password) { getCurrentWebClientContext().setSavedPassword(password); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#setSavedUserName(String) */ public void setSavedUserName(final String userName) { getCurrentWebClientContext().setSavedUserName(userName); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#setWebClient(WebClient) */ public void setWebClient(final WebClient webClient) { getCurrentWebClientContext().setWebClient(webClient); } /** * Delegates to current {@link WebClientContext} * * @see #getCurrentWebClientContext() * @see WebClientContext#suspendWindowListener() */ public void suspendWindowListener() { getCurrentWebClientContext().suspendWindowListener(); } /** * Gets the last background JS exception (if any). * This method should disappear when HtmlUnit offer better control possibilities for that. * This consumes the exception and next call will return <code>null</code> (unless a new error occurs) * @return the JS error */ public ScriptException getBackgroundJSError() { return backgroundJSError_.getAndSet(null); } /** * Sets the last background JS exception. * This method should disappear when HtmlUnit offer better control possibilities for that * @return the JS error */ public void setBackgroundJSError(final ScriptException e) { backgroundJSError_.set(e); } }