001: // Copyright © 2002-2005 Canoo Engineering AG, Switzerland.
002: package com.canoo.webtest.steps.request;
003:
004: import java.io.IOException;
005: import java.io.Serializable;
006: import java.net.URL;
007:
008: import org.apache.log4j.Logger;
009: import org.xml.sax.SAXException;
010:
011: import com.canoo.webtest.engine.Configuration;
012: import com.canoo.webtest.engine.Context;
013: import com.canoo.webtest.engine.StepExecutionException;
014: import com.canoo.webtest.interfaces.IConnectionInitializer;
015: import com.canoo.webtest.security.ConnectionInitializationException;
016: import com.canoo.webtest.steps.AbstractBrowserAction;
017: import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider;
018: import com.gargoylesoftware.htmlunit.Page;
019: import com.gargoylesoftware.htmlunit.WebRequestSettings;
020:
021: /**
022: * This is a helper class for all test specification steps
023: * that initiate a request.
024: * <p/>
025: * It offers common functionality like:
026: * preparing the request in case basic authentication is required,
027: * handling http error scenarios,
028: * reporting and saving away the response if successful.
029: *
030: * @author Carsten Seibert
031: * @author Marc Guillemot
032: * @author Paul King
033: */
034: public class TargetHelper implements Serializable {
035: private static final Logger LOG = Logger
036: .getLogger(TargetHelper.class);
037: public static final String CONNECTION_INITIALIZER_KEY = "webtest.connectioninitializer";
038: private String fUserName;
039: private String fPassword;
040: private final AbstractBrowserAction fStep;
041:
042: public TargetHelper(final AbstractBrowserAction step) {
043: fStep = step;
044: }
045:
046: public void setUsername(final String userName) {
047: fUserName = userName;
048: }
049:
050: public void setPassword(final String password) {
051: fPassword = password;
052: }
053:
054: /**
055: * Hook for test stubs in order to avoid invocation of a real request
056: *
057: * @param context The current test context.
058: * @param strUrl The URL to invoke.
059: */
060: public Page getResponse(final Context context, final String strUrl)
061: throws IOException, SAXException {
062: LOG.info("getting response for url: " + strUrl);
063: prepareConversationIfNeeded(context);
064: final URL url = new URL(strUrl);
065: return context.getWebClient().getPage(url);
066: }
067:
068: public Page getResponse(final Context context,
069: final WebRequestSettings settings) throws IOException,
070: SAXException {
071: LOG.info("getting response for url: " + settings.getURL());
072: prepareConversationIfNeeded(context);
073: return context.getWebClient().getPage(settings);
074: }
075:
076: /**
077: * Prepare the specified WebConversation for a request by setting
078: * user and password (if specified) and install a custom HostnameVerifier
079: * if required by the currently used protocol.
080: *
081: * @param context The current test context.
082: */
083: protected void prepareConversationIfNeeded(final Context context) {
084: if (context.isPrepared()) {
085: LOG
086: .debug("Conversation already prepared - attempting to skip preparation");
087: if (!hasSuppliedCredentials()) {
088: return; // already set up, keep https session throughout webtest
089: }
090: if (hasSuppliedCredentials()
091: && fUserName.equals(context.getSavedUserName())
092: && fPassword.equals(context.getSavedPassword())) {
093: return; // same username and password, nothing to do
094: }
095: LOG
096: .debug("Conversation already prepared - but username and password have changed - continuing preparation");
097: }
098: if (hasSuppliedCredentials()) {
099: LOG.info("Setting password for username: " + fUserName);
100: // credentials provider has already been set as DefaultCredentialsProvider
101: // in Setup (may already contain credentials for proxy)
102: final DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) context
103: .getWebClient().getCredentialsProvider();
104: credentialsProvider.addCredentials(fUserName, fPassword);
105: context.setSavedUserName(fUserName);
106: context.setSavedPassword(fPassword);
107: }
108:
109: final Configuration config = context.getConfig();
110: final String customInitializerClassName = config
111: .getExternalProperty(CONNECTION_INITIALIZER_KEY);
112: if (customInitializerClassName != null) {
113: invokeCustomInitializer(context, customInitializerClassName);
114: }
115: context.setPrepared(true);
116: }
117:
118: private boolean hasSuppliedCredentials() {
119: return fUserName != null && fPassword != null;
120: }
121:
122: protected void invokeCustomInitializer(final Context context,
123: final String customInitializerClassName) {
124: LOG.info("Using custom initializer: "
125: + customInitializerClassName);
126: try {
127: final Object object = Class.forName(
128: customInitializerClassName).newInstance();
129: final IConnectionInitializer customInitializer = (IConnectionInitializer) object;
130: customInitializer.initializeConnection(context.getConfig());
131: } catch (final ConnectionInitializationException e) {
132: final Throwable throwme = new StepExecutionException(
133: "ConnectionInitializer raised exception: "
134: + e.getMessage(), fStep);
135: throw (RuntimeException) throwme.fillInStackTrace();
136: } catch (final Exception e) {
137: LOG.info("Root exception from Connection Initializer", e);
138: final Throwable throwme = new StepExecutionException(
139: "Exception raised while trying to create custom ConnectionInitializer <"
140: + customInitializerClassName
141: + "> / Exception: " + e, fStep);
142: throw (RuntimeException) throwme.fillInStackTrace();
143: }
144: }
145: }
|