src/main/java/com/voxeo/tropo/Key.java
public static Key REQUIRED(Boolean value) {

	return createKey("required", value);
}
src/main/java/com/voxeo/tropo/actions/AskAction.java
@ValidKeys(keys = { "name", "required", "choices", "allowSignals", "attempts", "bargein", "minConfidence", "recognizer", "timeout", "sensitivity", "voice",
    "interdigitTimeout", "say", "speechCompleteTimeout", "speechIncompleteTimeout", "promptLogSecurity", "asrLogSecurity", "maskTemplate" })
@RequiredKeys(keys = { "choices", "say" })
public class AskAction extends JsonAction {

  private ActionSupportHandler<SayAction>      sayActionSupportHandler     = new ActionSupportHandler<SayAction>(SayAction.class);
  private ActionSupportHandler<ChoicesAction>  choicesActionSupportHandler = new ActionSupportHandler<ChoicesAction>(ChoicesAction.class);
  private ActionSupportHandler<NestedOnAction> onActionSupportHandler      = new ActionSupportHandler<NestedOnAction>(NestedOnAction.class);

  public AskAction() {

    super();
    setName("ask");
  }

  public AskAction(Key... keys) {

    super(keys);
    setName("ask");
  }

  public SayAction say(String text) {

    return say(VALUE(text));
  }

  public SayAction say(Key... keys) {

    return sayActionSupportHandler.build(this, keys);
  }

  public NestedOnAction on(Key... keys) {

    return onActionSupportHandler.build(this, keys);
  }

  public NestedOnAction on(String event, String next) {

    return on(EVENT(event), NEXT(next));
  }

  public ChoicesAction choices(Key... keys) {

    return choicesActionSupportHandler.build(this, keys);
  }

  public AskAction choices(String choice) {

    choices(VALUE(choice));
    return this;
  }

  public static class Choices {

    public Choices(String value) {
      this(value, null, null);
    }

    public Choices(String value, Mode mode) {
      this(value, mode, null);
    }

    public Choices(String value, Mode mode, String terminator) {
      if (value == null || value.trim().equals("")) {
        throw new TropoException("Missing required property: value of Choices");
      } else {
        this.value = value;
      }

      this.mode = mode;

      if (!(terminator == null || terminator.trim().equals(""))) {
        this.terminator = terminator;
      }
    }

    private String value;

    private Mode mode;

    private String terminator;

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    public Mode getMode() {
      return mode;
    }

    public void setMode(Mode mode) {
      this.mode = mode;
    }

    public String getTerminator() {
      return terminator;
    }

    public void setTerminator(String terminator) {
      this.terminator = terminator;
    }
  }

  public static class Say {

    public Say(String value) {
      this(value, null, null);
    }

    private Say(String value, Voice voice) {
      this(value, voice, null);
    }

    public Say(String value, String event) {
      this(value, null, event);
    }

    private Say(String value, Voice voice, String event) {
      this(value, null, null, null, null, voice, null, event);
    }

    private Say(String value, String[] allowSignals, As as, String name, Boolean required, Voice voice,
        String promptLogSecurity, String event) {
      if (value == null || value.trim().equals("")) {
        throw new TropoException("Missing required property: value of ask.say");
      } else {
        this.value = value;
      }
      this.allowSignals = allowSignals;
      this.as = as;
      this.name = name;
      this.required = required;
      this.voice = voice;
      if (promptLogSecurity != null && promptLogSecurity.trim().equalsIgnoreCase("suppress")) {
        this.promptLogSecurity = "suppress";
      }
      if (!(event == null || event.trim().equals(""))) {
        this.event = event;
      }
    }

    private String value;

    private String[] allowSignals;

    private As as;

    private String name;

    private Boolean required;

    private Voice voice;

    private String promptLogSecurity;
    
    private String event;

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    public String[] getAllowSignals() {
      return allowSignals;
    }

    public void setAllowSignals(String[] allowSignals) {
      this.allowSignals = allowSignals;
    }

    public As getAs() {
      return as;
    }

    public void setAs(As as) {
      this.as = as;
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public Boolean getRequired() {
      return required;
    }

    public void setRequired(Boolean required) {
      this.required = required;
    }

    public Voice getVoice() {
      return voice;
    }

    public void setVoice(Voice voice) {
      this.voice = voice;
    }

    public String getPromptLogSecurity() {
      return promptLogSecurity;
    }

    public void setPromptLogSecurity(String promptLogSecurity) {
      this.promptLogSecurity = promptLogSecurity;
    }

    public String getEvent() {
      return event;
    }

    public void setEvent(String event) {
      this.event = event;
    }
  }
}
src/main/java/com/voxeo/tropo/Key.java
public static Key TIMEOUT(Float value) {

	return createKey("timeout", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key NETWORK(Network value) {

	return createKey("network", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key FROM(String value) {

	return createKey("from", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key BEEP(Boolean value) {

	return createKey("beep", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key SENSITIVITY(Float value) {

	return createKey("sensitivity", value);
}
src/main/java/com/voxeo/tropo/Key.java
@Deprecated
public static Key EXIT_TONE(String value) {

	return createKey("exit_tone", value);
}
src/main/java/com/voxeo/tropo/actions/AnswerAction.java
@ValidKeys(keys = {"headers"})
public class AnswerAction extends JsonAction {

  private HeadersSupportHandler headersSupportHandler = new HeadersSupportHandler();

  public AnswerAction() {

    super();
    setName("answer");
  }

  public AnswerAction(Key... keys) {

    super(keys);
    setName("answer");
  }

  public HeadersAction headers(String[]... keys) {

    return headersSupportHandler.headers(this, keys);
  }
}
src/main/java/com/voxeo/tropo/Key.java
public static Key PASSWORD(String value) {

	return createKey("password", value);
}
src/main/java/com/voxeo/tropo/actions/StartRecordingAction.java
@ValidKeys(keys={"format","method","url","username","password","asyncUpload","transcriptionOutURI","transcriptionEmailFormat","transcriptionID","transcriptionLanguage"})
@RequiredKeys(keys={"url"})
public class StartRecordingAction extends JsonAction {

	public StartRecordingAction() {
		
		super();
		setName("startRecording");
	}
	
	public StartRecordingAction(Key... keys) {
	
		super(keys);
		setName("startRecording");
	}

	@Override
  protected void validate() throws TropoException {
    
    super.validate();
    checkUrl("url");
  }
}
src/main/java/com/voxeo/tropo/actions/ChoicesAction.java
@ValidKeys(keys={"value","mode","terminator"})
public class ChoicesAction extends JsonAction {

	public ChoicesAction() {
		
		super();
		setName("choices");
	}
	
	public ChoicesAction(Key... keys) {
	
		super(keys);
		setName("choices");
	}	
	
	@Override
	protected void validate() throws TropoException {
		
		super.validate();
		Object mode = get("mode");
		if (mode != null) {
			for(Mode modeValue : Mode.values()) {
			    if(modeValue.toString().equals(mode)){
			        return;
			    }
			}
			throw new TropoException("If mode is provided, only 'dtmf', 'speech' or 'any' is supported");
		}
	}
}
src/main/java/com/voxeo/tropo/Key.java
public static Key TO(String value) {

	return createKey("to", value);
}
src/main/java/com/voxeo/tropo/actions/OnAction.java
@ValidKeys(keys={"next","event","say","post"})
@RequiredKeys(keys={"event"})
public class OnAction extends JsonAction {

	private ActionSupportHandler<SayAction> sayActionSupportHandler = new ActionSupportHandler<SayAction>(SayAction.class);	

	public OnAction() {
		
		super();
		setName("on");
	}
	
	public OnAction(Key... keys) {
	
		super(keys);
		setName("on");
	}	
	
	public SayAction say(String text) {

		return say(VALUE(text));
	}
	
	public SayAction say(Key... keys) {

		return sayActionSupportHandler.build(this, keys);
	}

  public static class Say {

    private String value;

    private Voice voice;

    public Say(String value) {
      this(value, null);
    }

    public Say(String value, Voice voice) {

      if (value == null || value.trim().equals("")) {
        throw new TropoException("Missing required property: value of on.say");
      }
      this.value = value;
      this.voice = voice;
    }

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    public Voice getVoice() {
      return voice;
    }

    public void setVoice(Voice voice) {
      this.voice = voice;
    }
  }
}
src/main/java/com/voxeo/tropo/Key.java
public static Key BARGEIN(Boolean value) {

	return createKey("bargein", value);
}
src/main/java/com/voxeo/tropo/actions/WaitAction.java
@ValidKeys(keys={"allowSignals", "milliseconds"})
@RequiredKeys(keys={"milliseconds"})
public class WaitAction extends JsonAction {

    public WaitAction() {
        super();
        setName("wait");
    }

    public WaitAction(Key... keys) {
        super(keys);
        setName("wait");
    }
}
src/main/java/com/voxeo/tropo/actions/ArrayBackedJsonAction.java
public abstract class ArrayBackedJsonAction extends JsonAction {
    
    public ArrayBackedJsonAction(String name) {
    
        super();
        setName(name);
        put(getName(), new JsonArray());
    }
    
    @Override
    public void reset() {
    
        super.reset();
        put(getName(), new JsonArray());
    }
    
    @Override
    protected void accumulate(String key, Action value) {
    
        addToArray(getName(), key, value);
    }
    
    protected boolean isEmpty() {
    
        JsonArray array = getJSONArray(getName());
        return array.size() == 0;
    }
}
src/main/java/com/voxeo/tropo/actions/RedirectAction.java
@ValidKeys(keys={"to","name","required"})
@RequiredKeys(keys={"to"})
public class RedirectAction extends JsonAction {

	public RedirectAction() {
		
		super();
		setName("redirect");
	}
	
	public RedirectAction(Key... keys) {
	
		super(keys);
		setName("redirect");
	}
	
	@Override
	protected void validate() throws TropoException {

		super.validate();
		if (getParent() != null) {
			if (!(getParent() instanceof Tropo)) {
				throw new TropoException("Redirect should only be used alone and before the session is answered, use transfer instead");
			}
		}
	}
}
src/main/java/com/voxeo/tropo/Key.java
public static Key FORMAT(Format value) {

	return createKey("format", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key CHANNEL(Channel value) {

	return createKey("channel", value);
}
src/main/java/com/voxeo/tropo/enums/Network.java
public enum Network {
	SMS, AIM, MSN, JABBER, YAHOO, GTALK, TWITTER, PSTN, SIP, MMS
}
src/main/java/com/voxeo/tropo/actions/RecordAction.java
@ValidKeys(keys={"name","attempts","allowSignals","bargein","beep","choices","format","maxSilence","maxTime","method",
        "required","transcription","url","password","username","timeout","voice","interdigitTimeout", "asyncUpload","say","promptLogSecurity","sensitivity"})
@RequiredKeys(keys={"url"})
public class RecordAction extends JsonAction {
	
	private ActionSupportHandler<SayAction> sayActionSupportHandler = new ActionSupportHandler<SayAction>(SayAction.class);	
	private ActionSupportHandler<ChoicesAction> choicesActionSupportHandler = new ActionSupportHandler<ChoicesAction>(ChoicesAction.class);	
	private ActionSupportHandler<TranscriptionAction> transcriptionActionSupportHandler = new ActionSupportHandler<TranscriptionAction>(TranscriptionAction.class);	

	public RecordAction() {
		
		super();
		setName("record");
	}
	
	public RecordAction(Key... keys) {
	
		super(keys);
		setName("record");
	}	
	
	public SayAction say(String text) {

		return say(VALUE(text));
	}
	
	public SayAction say(Key... keys) {

		return sayActionSupportHandler.build(this, keys);
	}	
	
	public ChoicesAction choices(Key... keys) {

		return choicesActionSupportHandler.build(this, keys);
	}
	
	public ChoicesAction choices(String value) {

		return choices(VALUE(value));
	}

	public TranscriptionAction transcription(Key... keys) {

		return transcriptionActionSupportHandler.build(this, keys);
	}	
	
	public TranscriptionAction transcription(String id, String url, String emailFormat, String language) {

		return transcription(ID(id), URL(url), EMAIL_FORMAT(emailFormat), Key.LANGUAGE(language));
	}
	
  public static class Say {
    private String value;

    private String event;

    public Say(String value) {
      if (value == null || value.trim().equals(""))
        throw new TropoException("Missing required property: value of record.say");
      this.value = value;
    }

    public Say(String value, String event) {
      if (value == null || value.trim().equals(""))
        throw new TropoException("Missing required property: value of record.say");
      if (!("timeout".equals(event)))
        throw new TropoException("For record, the only possible event is 'timeout'.");
      this.value = value;
      this.event = "timeout";
    }

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    public String getEvent() {
      return event;
    }

    public void setEvent(String event) {
      this.event = event;
    }
  }
  
  public static class Transcription {
    private String id;

    private String url;

    private EmailFormat emailFormat;

    public Transcription(String url) {
      super();
      this.url = url;
    }

    public Transcription(String id, String url) {
      super();
      this.id = id;
      this.url = url;
    }

    public Transcription(String id, String url, EmailFormat emailFormat) {
      super();
      this.id = id;
      this.url = url;
      this.emailFormat = emailFormat;
    }

    public String getId() {
      return id;
    }

    public void setId(String id) {
      this.id = id;
    }

    public String getUrl() {
      return url;
    }

    public void setUrl(String url) {
      this.url = url;
    }

    public EmailFormat getEmailFormat() {
      return emailFormat;
    }

    public void setEmailFormat(EmailFormat emailFormat) {
      this.emailFormat = emailFormat;
    }
  }

  public static class Url {
    private String url;

    private String username;

    private String password;

    private String method;

    public Url(String url) {
      super();
      this.url = url;
    }

    public Url(String url, String username, String password, String method) {
      super();
      if (url == null || url.trim().equals("")) {
        throw new TropoException("Missing required property: url of Url");
      }
      this.url = url;
      this.username = username;
      this.password = password;
      this.method = method;
    }

    public String getUrl() {
      return url;
    }

    public void setUrl(String url) {
      this.url = url;
    }

    public String getUsername() {
      return username;
    }

    public void setUsername(String username) {
      this.username = username;
    }

    public String getPassword() {
      return password;
    }

    public void setPassword(String password) {
      this.password = password;
    }

    public String getMethod() {
      return method;
    }

    public void setMethod(String method) {
      this.method = method;
    }
  }
	
	@Override
	protected void validate() throws TropoException {
		
		super.validate();
		checkUrl("url");
	}
}
src/main/java/com/voxeo/tropo/Key.java
public static Key EVENT(String value) {

	return createKey("event", value);
}
src/main/java/com/voxeo/tropo/enums/LogSecurityState.java
public enum LogSecurityState {

  NONE, SUPPRESS;

  @Override
  public String toString() {

    return super.toString().toLowerCase();
  }
}
src/main/java/com/voxeo/tropo/Key.java
public static Key MILLISECONDS(Long milliseconds) {

    return createKey("milliseconds", milliseconds);
}
src/main/java/com/voxeo/tropo/actions/SayAction.java
@ValidKeys(keys={"name","value","allowSignals","voice","as","required","promptLogSecurity","media"})
@RequiredKeys(keys={"value"})
public class SayAction extends ArrayAction {

	public SayAction(String text) {

		setName("say");
		JsonObject item = new JsonObject();
		item.addProperty("value", text);
		add(item);		
	}	
	
	public SayAction(Key... keys) {
	
		super(keys);		
		setName("say");
	}
	
	public SayAction say(String text) {

		return say(VALUE(text));
	}
	
	public SayAction say(Key... keys) {

		add(buildObjectFromKeys(keys));		
		return this;
	}
}
src/main/java/com/voxeo/tropo/Key.java
public static Key USERNAME(String value) {

	return createKey("username", value);
}
src/main/java/com/voxeo/tropo/actions/CallAction.java
@ValidKeys(keys = { "to", "allowSignals", "answerOnMedia", "channel", "from", "headers", "name", "network", "required", "timeout", "machineDetection", "voice", "callbackUrl", "promptLogSecurity", "label" })
@RequiredKeys(keys = { "to" })
public class CallAction extends JsonAction {

  private ActionSupportHandler<StartRecordingAction> startRecordingActionSupportHandler = new ActionSupportHandler<StartRecordingAction>(StartRecordingAction.class);
  private HeadersSupportHandler                      headersSupportHandler              = new HeadersSupportHandler();

  public CallAction() {

    super();
    setName("call");
  }

  public CallAction(Key... keys) {

    super(keys);
    setName("call");
  }

  public StartRecordingAction startRecording(Key... keys) {

    return startRecordingActionSupportHandler.build(this, keys);
  }

  public HeadersAction headers(String[]... keys) {

    return headersSupportHandler.headers(this, keys);
  }
}
src/main/java/com/voxeo/tropo/Key.java
@Deprecated
public static Key SEND_TONES(Boolean value) {

	return createKey("send_tones", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key NAME(String value) {

	return createKey("name", value);
}
src/main/java/com/voxeo/tropo/Key.java
public static Key URL(String value) {

	return createKey("url", value);
}
src/main/java/com/voxeo/tropo/enums/Format.java
public enum Format {

	WAV, MP3, AU;
	
	@Override public String toString() {
		
		String s = super.toString();
		return "audio/"+s.toLowerCase();
	}
}
src/main/java/com/voxeo/tropo/actions/MessageAction.java
@ValidKeys(keys={"say","to","answerOnMedia","channel","from","name","network","required","timeout","voice","promptLogSecurity"})
@RequiredKeys(keys={"to","say"})
public class MessageAction extends JsonAction {

	private ActionSupportHandler<SayAction> sayActionSupportHandler = new ActionSupportHandler<SayAction>(SayAction.class);	

	public MessageAction() {
		
		super();
		setName("message");
	}
	
	public MessageAction(Key... keys) {
	
		super(keys);
		setName("message");
	}
	
	public static class Say {

    public Say(String value) {

      if (value == null || value.trim().equals("")) {
        throw new TropoException("Missing required property: value of message.say");
      }

      this.value = value;
    }

    public Say(String value, String[] medias) {

      if (value == null || value.trim().equals("")) {
        throw new TropoException("Missing required property: value of message.say");
      }

      this.value = value;
      this.media = medias;
    }

    private String value;
    private String[] media;

    public String getValue() {
      return value;
    }

    public void setValue(String value) {
      this.value = value;
    }

    public String[] getMedia() {
      return media;
    }

    public void setMedia(String[] media) {
      this.media = media;
    }

	}
	
	public SayAction say(String text) {

		return say(VALUE(text));
	}
	
	public SayAction say(Key... keys) {

		return sayActionSupportHandler.build(this, keys);
	}
}
src/main/java/com/voxeo/tropo/Key.java
public static Key NEXT(String value) {

	return createKey("next", value);
}
src/main/java/com/voxeo/tropo/actions/ConferenceAction.java
@ValidKeys(keys={"name","allowSignals","mute","on","playTones","terminator","id","send_tones","exit_tone","interdigitTimeout","joinPrompt","leavePrompt","required","promptLogSecurity"})
@RequiredKeys(keys={"id"})
public class ConferenceAction extends JsonAction {

	private ActionSupportHandler<NestedOnAction> onActionSupportHandler = new ActionSupportHandler<NestedOnAction>(NestedOnAction.class);	

	public ConferenceAction() {
		
		super();
		setName("conference");
	}
	
	public ConferenceAction(Key... keys) {
	
		super(keys);
		setName("conference");
	}
	
	public NestedOnAction on(Key... keys) {

		return onActionSupportHandler.build(this, keys);
	}
	
	public NestedOnAction on(String event, String next) {

		return on(EVENT(event), NEXT(next));
	}
}
src/main/java/com/voxeo/tropo/actions/TransferAction.java
@ValidKeys(keys={"to","allowSignals","choices","from","headers","name","on","required","ringRepeat","timeout","answerOnMedia","interdigitTimeout","machineDetection","playTones","voice","callbackUrl","promptLogSecurity","label"})
@RequiredKeys(keys={"to"})
public class TransferAction extends JsonAction {

	private ActionSupportHandler<NestedOnAction> onRecordingActionSupportHandler = new ActionSupportHandler<NestedOnAction>(NestedOnAction.class);
	private ActionSupportHandler<ChoicesAction> choicesRecordingActionSupportHandler = new ActionSupportHandler<ChoicesAction>(ChoicesAction.class);
	private HeadersSupportHandler headersSupportHandler = new HeadersSupportHandler();

	public TransferAction() {

		super();
		setName("transfer");
	}

	public TransferAction(Key... keys) {

		super(keys);
		setName("transfer");
	}

	public NestedOnAction on(Key... keys) {

		return onRecordingActionSupportHandler.build(this, keys);
	}

	public NestedOnAction on(String event, String next) {

		return on(EVENT(event), NEXT(next));
	}

	public ChoicesAction choices(Key... keys) {

		return choicesRecordingActionSupportHandler.build(this, keys);
	}

	public AskAction choices(String choice) {

		return (AskAction)and(choices(VALUE(choice)));
	}

	public HeadersAction headers(String[]... keys) {

		return headersSupportHandler.headers(this, keys);
	}
}


Question: package com.voxeo.tropo;
import static com.voxeo.tropo.Key.BARGEIN;
import static com.voxeo.tropo.Key.BEEP;
import static com.voxeo.tropo.Key.CHANNEL;
import static com.voxeo.tropo.Key.EVENT;
import static com.voxeo.tropo.Key.EXIT_TONE;
import static com.voxeo.tropo.Key.FORMAT;
import static com.voxeo.tropo.Key.FROM;
import static com.voxeo.tropo.Key.MILLISECONDS;
import static com.voxeo.tropo.Key.NAME;
import static com.voxeo.tropo.Key.NETWORK;
import static com.voxeo.tropo.Key.NEXT;
import static com.voxeo.tropo.Key.PASSWORD;
import static com.voxeo.tropo.Key.REQUIRED;
import static com.voxeo.tropo.Key.SEND_TONES;
import static com.voxeo.tropo.Key.SENSITIVITY;
import static com.voxeo.tropo.Key.TIMEOUT;
import static com.voxeo.tropo.Key.TO;
import static com.voxeo.tropo.Key.URL;
import static com.voxeo.tropo.Key.USERNAME;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.HttpClient;
import com.voxeo.tropo.actions.AnswerAction;
import com.voxeo.tropo.actions.ArrayBackedJsonAction;
import com.voxeo.tropo.actions.AskAction;
import com.voxeo.tropo.actions.CallAction;
import com.voxeo.tropo.actions.ChoicesAction;
import com.voxeo.tropo.actions.ConferenceAction;
import com.voxeo.tropo.actions.MessageAction;
import com.voxeo.tropo.actions.OnAction;
import com.voxeo.tropo.actions.RecordAction;
import com.voxeo.tropo.actions.RedirectAction;
import com.voxeo.tropo.actions.SayAction;
import com.voxeo.tropo.actions.StartRecordingAction;
import com.voxeo.tropo.actions.TransferAction;
import com.voxeo.tropo.actions.WaitAction;
import com.voxeo.tropo.enums.Channel;
import com.voxeo.tropo.enums.Format;
import com.voxeo.tropo.enums.LogSecurityState;
import com.voxeo.tropo.enums.Network;
import support.ActionSupportHandler;







public class Tropo extends ArrayBackedJsonAction {

  private TropoParser                                parser;
  private String                                     baseUrl                            = "https://api.tropo.com/v1/";

  private ActionSupportHandler<SayAction>            sayActionSupportHandler            = new ActionSupportHandler<SayAction>(SayAction.class);
  private ActionSupportHandler<AskAction>            askActionSupportHandler            = new ActionSupportHandler<AskAction>(AskAction.class);
  private ActionSupportHandler<ConferenceAction>     conferenceActionSupportHandler     = new ActionSupportHandler<ConferenceAction>(ConferenceAction.class);
  private ActionSupportHandler<ChoicesAction>        choicesActionSupportHandler        = new ActionSupportHandler<ChoicesAction>(ChoicesAction.class);
  private ActionSupportHandler<OnAction>             onActionSupportHandler             = new ActionSupportHandler<OnAction>(OnAction.class);
  private ActionSupportHandler<RecordAction>         recordActionSupportHandler         = new ActionSupportHandler<RecordAction>(RecordAction.class);
Answer:   private ActionSupportHandler<RedirectAction>       redirectActionSupportHandler       = new ActionSupportHandler<RedirectAction>(RedirectAction.class);