@Override protected void init(ServletConfig config) { maxSize = Constants.MAX_POOL_SIZE; String maxSizeS = getOption(config, OPTION_MAXSIZE, null); if (maxSizeS != null) { maxSize = Integer.parseInt(maxSizeS); if (maxSize < 0) { maxSize = Constants.MAX_POOL_SIZE; } } perThread = new ThreadLocal<PerThreadData>() { @Override protected PerThreadData initialValue() { PerThreadData ptd = new PerThreadData(); ptd.handlers = new Tag[maxSize]; ptd.current = -1; perThreadDataVector.addElement(ptd); return ptd; } }; }
protected void init(ServletConfig config) { int maxSize = -1; String maxSizeS = getOption(config, OPTION_MAXSIZE, null); if (maxSizeS != null) { try { maxSize = Integer.parseInt(maxSizeS); } catch (Exception ex) { maxSize = -1; } } if (maxSize < 0) { maxSize = Constants.MAX_POOL_SIZE; } this.handlers = new Tag[maxSize]; this.current = -1; instanceManager = InstanceManagerFactory.getInstanceManager(config); }
/** * Determine whether the supplied {@link Tag} has any ancestor tag * of the supplied type. * @param tag the tag whose ancestors are to be checked * @param ancestorTagClass the ancestor {@link Class} being searched for * @return {@code true} if the supplied {@link Tag} has any ancestor tag * of the supplied type * @throws IllegalArgumentException if either of the supplied arguments is {@code null}; * or if the supplied {@code ancestorTagClass} is not type-assignable to * the {@link Tag} class */ public static boolean hasAncestorOfType(Tag tag, Class<?> ancestorTagClass) { Assert.notNull(tag, "Tag cannot be null"); Assert.notNull(ancestorTagClass, "Ancestor tag class cannot be null"); if (!Tag.class.isAssignableFrom(ancestorTagClass)) { throw new IllegalArgumentException( "Class '" + ancestorTagClass.getName() + "' is not a valid Tag type"); } Tag ancestor = tag.getParent(); while (ancestor != null) { if (ancestorTagClass.isAssignableFrom(ancestor.getClass())) { return true; } ancestor = ancestor.getParent(); } return false; }
protected void init(ServletConfig config) { maxSize = Constants.MAX_POOL_SIZE; String maxSizeS = getOption(config, OPTION_MAXSIZE, null); if (maxSizeS != null) { maxSize = Integer.parseInt(maxSizeS); if (maxSize < 0) { maxSize = Constants.MAX_POOL_SIZE; } } perThread = new ThreadLocal() { protected Object initialValue() { PerThreadData ptd = new PerThreadData(); ptd.handlers = new Tag[maxSize]; ptd.current = -1; perThreadDataVector.addElement(ptd); return ptd; } }; }
protected void init( ServletConfig config ) { int maxSize=-1; String maxSizeS=getOption(config, OPTION_MAXSIZE, null); if( maxSizeS != null ) { try { maxSize=Integer.parseInt(maxSizeS); } catch( Exception ex) { maxSize=-1; } } if( maxSize <0 ) { maxSize=Constants.MAX_POOL_SIZE; } this.handlers = new Tag[maxSize]; this.current = -1; instanceManager = InstanceManagerFactory.getInstanceManager(config); }
/** * Gets the next available tag handler from this tag handler pool, * instantiating one if this tag handler pool is empty. * * @param handlerClass Tag handler class * * @return Reused or newly instantiated tag handler * * @throws JspException if a tag handler cannot be instantiated */ public Tag get(Class handlerClass) throws JspException { Tag handler; synchronized( this ) { if (current >= 0) { handler = handlers[current--]; return handler; } } // Out of sync block - there is no need for other threads to // wait for us to construct a tag for this thread. try { if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { return (Tag) instanceManager.newInstance(handlerClass.getName(), handlerClass.getClassLoader()); } else { Tag instance = (Tag) handlerClass.newInstance(); if (Constants.INJECT_TAGS) { instanceManager.newInstance(instance); } return instance; } } catch (Exception e) { throw new JspException(e.getMessage(), e); } }
/** * Adds the given tag handler to this tag handler pool, unless this tag * handler pool has already reached its capacity, in which case the tag * handler's release() method is called. * * @param handler Tag handler to add to this tag handler pool */ public void reuse(Tag handler) { synchronized( this ) { if (current < (handlers.length - 1)) { handlers[++current] = handler; return; } } // There is no need for other threads to wait for us to release handler.release(); if (Constants.INJECT_TAGS) { try { instanceManager.destroyInstance(handler); } catch (Exception e) { log.warn("Error processing preDestroy on tag instance of " + handler.getClass().getName(), e); } } }
@Override public int doStartTag() throws JspException { HttpServletRequest request = (HttpServletRequest) pageContext.getRequest(); String path = WebUtil.getBaseServerURL() + request.getContextPath(); if (!path.endsWith("/")) { path += "/"; } try { JspWriter writer = pageContext.getOut(); writer.print(path); } catch (IOException e) { WebAppURLTag.log.error("ServerURLTag unable to write out server URL due to IOException. ", e); throw new JspException(e); } return Tag.SKIP_BODY; }
@Override public int doStartTag() throws JspException { HttpSession ss = SessionManager.getSession(); if (ss != null) { UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); if (user != null) { processProperty(user); } else { UserTag.log.warn("UserTag unable to access user details as userDTO is missing. Session is " + ss); } } else { UserTag.log.warn("UserTag unable to access user details as shared session is missing"); } return Tag.SKIP_BODY; }
/** * Does two things: * <ul> * <li>Stops the page if the corresponding attribute has been set</li> * <li>Prints a message another tag encloses this one.</li> * </ul> */ public int doEndTag() throws JspTagException { //get the parent if any Tag parent = this.getParent(); if (parent != null) { try { JspWriter out = this.pageContext.getOut(); out.println("This tag has a parent. <BR>"); } catch (IOException e) { throw new JspTagException(e.getMessage()); } } if (this.stopPage) { return Tag.SKIP_PAGE; } return Tag.EVAL_PAGE; }
/** * Gets the next available tag handler from this tag handler pool, * instantiating one if this tag handler pool is empty. * * @param handlerClass * Tag handler class * @return Reused or newly instantiated tag handler * @throws JspException * if a tag handler cannot be instantiated */ public Tag get(Class<? extends Tag> handlerClass) throws JspException { Tag handler; synchronized (this) { if (current >= 0) { handler = handlers[current--]; return handler; } } // Out of sync block - there is no need for other threads to // wait for us to construct a tag for this thread. try { if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { return (Tag) instanceManager.newInstance(handlerClass.getName(), handlerClass.getClassLoader()); } else { Tag instance = handlerClass.newInstance(); instanceManager.newInstance(instance); return instance; } } catch (Exception e) { Throwable t = ExceptionUtils.unwrapInvocationTargetException(e); ExceptionUtils.handleThrowable(t); throw new JspException(e.getMessage(), t); } }
@Override public String renderTag(TagSupport tag, PageContext pageContext, String body) throws Exception { StringWriter strWriter = new StringWriter(); HttpServletResponse response = mock(HttpServletResponse.class); when(response.getWriter()).thenReturn(new PrintWriter(strWriter, true)); if (!mockingDetails(pageContext).isSpy()) { pageContext = spy(pageContext); } JspWriter jspWriter = new JspWriterImpl(response); doReturn(jspWriter).when(pageContext).getOut(); tag.setPageContext(pageContext); if (Tag.EVAL_BODY_INCLUDE == tag.doStartTag()) { jspWriter.flush(); strWriter.write(body); } jspWriter.flush(); tag.doEndTag(); jspWriter.flush(); tag.release(); return strWriter.toString(); }
@Test public void simpleBindWithHtmlEscaping() throws Exception { final String NAME = "Rob \"I Love Mangos\" Harrop"; final String HTML_ESCAPED_NAME = "Rob "I Love Mangos" Harrop"; this.tag.setPath("name"); this.rob.setName(NAME); assertEquals(Tag.SKIP_BODY, this.tag.doStartTag()); String output = getOutput(); assertTagOpened(output); assertTagClosed(output); assertContainsAttribute(output, "type", getType()); assertValueAttribute(output, HTML_ESCAPED_NAME); }
@Test public void withErrors() throws Exception { this.tag.setPath("name"); this.tag.setCssClass("good"); this.tag.setCssErrorClass("bad"); BeanPropertyBindingResult errors = new BeanPropertyBindingResult(this.rob, COMMAND_NAME); errors.rejectValue("name", "some.code", "Default Message"); errors.rejectValue("name", "too.short", "Too Short"); exposeBindingResult(errors); assertEquals(Tag.SKIP_BODY, this.tag.doStartTag()); String output = getOutput(); assertTagOpened(output); assertTagClosed(output); assertContainsAttribute(output, "type", getType()); assertValueAttribute(output, "Rob"); assertContainsAttribute(output, "class", "bad"); }
@Test public void messageWithVar() throws JspException { PageContext pc = createPageContext(); MessageTag tag = new MessageTag(); tag.setPageContext(pc); tag.setText("text & text"); tag.setVar("testvar"); tag.doStartTag(); assertEquals("Correct doEndTag return value", Tag.EVAL_PAGE, tag.doEndTag()); assertEquals("text & text", pc.getAttribute("testvar")); tag.release(); // try to reuse tag.setPageContext(pc); tag.setCode("test"); tag.setVar("testvar"); tag.doStartTag(); assertEquals("Correct doEndTag return value", Tag.EVAL_PAGE, tag.doEndTag()); assertEquals("Correct message", "test message", pc.getAttribute("testvar")); }
@Test public void bindTagWithIndexedProperties() throws JspException { PageContext pc = createPageContext(); IndexedTestBean tb = new IndexedTestBean(); Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); errors.rejectValue("array[0]", "code1", "message1"); errors.rejectValue("array[0]", "code2", "message2"); pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); BindTag tag = new BindTag(); tag.setPageContext(pc); tag.setPath("tb.array[0]"); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); assertTrue("Has status variable", status != null); assertTrue("Correct expression", "array[0]".equals(status.getExpression())); assertTrue("Value is TestBean", status.getValue() instanceof TestBean); assertTrue("Correct value", "name0".equals(((TestBean) status.getValue()).getName())); assertTrue("Correct isError", status.isError()); assertTrue("Correct errorCodes", status.getErrorCodes().length == 2); assertTrue("Correct errorMessages", status.getErrorMessages().length == 2); assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessages()[0])); assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); }
@Test public void withCustomBinder() throws Exception { this.tag.setPath("myFloat"); BeanPropertyBindingResult errors = new BeanPropertyBindingResult(this.bean, COMMAND_NAME); errors.getPropertyAccessor().registerCustomEditor(Float.class, new SimpleFloatEditor()); exposeBindingResult(errors); assertEquals(Tag.SKIP_BODY, this.tag.doStartTag()); String output = getOutput(); assertTagOpened(output); assertTagClosed(output); assertContainsAttribute(output, "type", "hidden"); assertContainsAttribute(output, "value", "12.34f"); }
@Test public void withExplicitNonWhitespaceBodyContent() throws Exception { String mockContent = "This is some explicit body content"; this.tag.setBodyContent(new MockBodyContent(mockContent, getWriter())); // construct an errors instance of the tag TestBean target = new TestBean(); target.setName("Rob Harrop"); Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); errors.rejectValue("name", "some.code", "Default Message"); exposeBindingResult(errors); int result = this.tag.doStartTag(); assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); result = this.tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, result); assertEquals(mockContent, getOutput()); }
@Test public void withExplicitEmptyWhitespaceBodyContent() throws Exception { this.tag.setBodyContent(new MockBodyContent("", getWriter())); // construct an errors instance of the tag TestBean target = new TestBean(); target.setName("Rob Harrop"); Errors errors = new BeanPropertyBindingResult(target, COMMAND_NAME); errors.rejectValue("name", "some.code", "Default Message"); exposeBindingResult(errors); int result = this.tag.doStartTag(); assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); result = this.tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, result); String output = getOutput(); assertElementTagOpened(output); assertElementTagClosed(output); assertContainsAttribute(output, "id", "name.errors"); assertBlockTagContains(output, "Default Message"); }
private void assertWhenNoErrorsExistingMessagesInScopeAreNotClobbered(int scope) throws JspException { String existingAttribute = "something"; getPageContext().setAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, existingAttribute, scope); Errors errors = new BeanPropertyBindingResult(new TestBean(), "COMMAND_NAME"); exposeBindingResult(errors); int result = this.tag.doStartTag(); assertEquals(Tag.SKIP_BODY, result); result = this.tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, result); String output = getOutput(); assertEquals(0, output.length()); assertEquals(existingAttribute, getPageContext().getAttribute(ErrorsTag.MESSAGES_ATTRIBUTE, scope)); }
@Test public void bindTagWithMappedProperties() throws JspException { PageContext pc = createPageContext(); IndexedTestBean tb = new IndexedTestBean(); Errors errors = new ServletRequestDataBinder(tb, "tb").getBindingResult(); errors.rejectValue("map[key1]", "code1", "message1"); errors.rejectValue("map[key1]", "code2", "message2"); pc.getRequest().setAttribute(BindingResult.MODEL_KEY_PREFIX + "tb", errors); BindTag tag = new BindTag(); tag.setPageContext(pc); tag.setPath("tb.map[key1]"); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); BindStatus status = (BindStatus) pc.getAttribute(BindTag.STATUS_VARIABLE_NAME, PageContext.REQUEST_SCOPE); assertTrue("Has status variable", status != null); assertTrue("Correct expression", "map[key1]".equals(status.getExpression())); assertTrue("Value is TestBean", status.getValue() instanceof TestBean); assertTrue("Correct value", "name4".equals(((TestBean) status.getValue()).getName())); assertTrue("Correct isError", status.isError()); assertTrue("Correct errorCodes", status.getErrorCodes().length == 2); assertTrue("Correct errorMessages", status.getErrorMessages().length == 2); assertTrue("Correct errorCode", "code1".equals(status.getErrorCodes()[0])); assertTrue("Correct errorCode", "code2".equals(status.getErrorCodes()[1])); assertTrue("Correct errorMessage", "message1".equals(status.getErrorMessages()[0])); assertTrue("Correct errorMessage", "message2".equals(status.getErrorMessages()[1])); }
@Test public void messageTagWithCode() throws JspException { PageContext pc = createPageContext(); final StringBuffer message = new StringBuffer(); MessageTag tag = new MessageTag() { @Override protected void writeMessage(String msg) { message.append(msg); } }; tag.setPageContext(pc); tag.setCode("test"); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); assertEquals("Correct doEndTag return value", Tag.EVAL_PAGE, tag.doEndTag()); assertEquals("Correct message", "test message", message.toString()); }
@Test @SuppressWarnings("serial") public void themeTag() throws JspException { PageContext pc = createPageContext(); final StringBuffer message = new StringBuffer(); ThemeTag tag = new ThemeTag() { @Override protected void writeMessage(String msg) { message.append(msg); } }; tag.setPageContext(pc); tag.setCode("themetest"); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); assertEquals("Correct doEndTag return value", Tag.EVAL_PAGE, tag.doEndTag()); assertEquals("theme test message", message.toString()); }
@Test @SuppressWarnings("rawtypes") public void withJavaEnum() throws Exception { GenericBean testBean = new GenericBean(); testBean.setCustomEnum(CustomEnum.VALUE_1); getPageContext().getRequest().setAttribute("testBean", testBean); String selectName = "testBean.customEnum"; getPageContext().setAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE, new BindStatus(getRequestContext(), selectName, false)); this.tag.setValue("VALUE_1"); int result = this.tag.doStartTag(); assertEquals(BodyTag.EVAL_BODY_BUFFERED, result); result = this.tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, result); String output = getWriter().toString(); assertOptionTagOpened(output); assertOptionTagClosed(output); assertContainsAttribute(output, "value", "VALUE_1"); assertContainsAttribute(output, "selected", "selected"); }
@Test public void withSingleValueNull() throws Exception { this.bean.setName(null); this.tag.setPath("name"); this.tag.setValue("Rob Harrop"); int result = this.tag.doStartTag(); assertEquals(Tag.SKIP_BODY, result); String output = getOutput(); // wrap the output so it is valid XML output = "<doc>" + output + "</doc>"; SAXReader reader = new SAXReader(); Document document = reader.read(new StringReader(output)); Element checkboxElement = (Element) document.getRootElement().elements().get(0); assertEquals("input", checkboxElement.getName()); assertEquals("checkbox", checkboxElement.attribute("type").getValue()); assertEquals("name", checkboxElement.attribute("name").getValue()); assertNull(checkboxElement.attribute("checked")); assertEquals("Rob Harrop", checkboxElement.attribute("value").getValue()); }
@Test public void withMultiValueUnchecked() throws Exception { this.tag.setPath("stringArray"); this.tag.setValue("abc"); int result = this.tag.doStartTag(); assertEquals(Tag.SKIP_BODY, result); String output = getOutput(); // wrap the output so it is valid XML output = "<doc>" + output + "</doc>"; SAXReader reader = new SAXReader(); Document document = reader.read(new StringReader(output)); Element checkboxElement = (Element) document.getRootElement().elements().get(0); assertEquals("input", checkboxElement.getName()); assertEquals("checkbox", checkboxElement.attribute("type").getValue()); assertEquals("stringArray", checkboxElement.attribute("name").getValue()); assertNull(checkboxElement.attribute("checked")); assertEquals("abc", checkboxElement.attribute("value").getValue()); }
@Test public void withObjectChecked() throws Exception { this.tag.setPath("date"); this.tag.setValue(getDate()); int result = this.tag.doStartTag(); assertEquals(Tag.SKIP_BODY, result); String output = getOutput(); // wrap the output so it is valid XML output = "<doc>" + output + "</doc>"; SAXReader reader = new SAXReader(); Document document = reader.read(new StringReader(output)); Element checkboxElement = (Element) document.getRootElement().elements().get(0); assertEquals("input", checkboxElement.getName()); assertEquals("checkbox", checkboxElement.attribute("type").getValue()); assertEquals("date", checkboxElement.attribute("name").getValue()); assertEquals("checked", checkboxElement.attribute("checked").getValue()); assertEquals(getDate().toString(), checkboxElement.attribute("value").getValue()); }
@Test public void paramWithValueThenReleaseThenBodyValue() throws JspException { tag.setName("name1"); tag.setValue("value1"); int action = tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, action); assertEquals("name1", parent.getParam().getName()); assertEquals("value1", parent.getParam().getValue()); tag.release(); parent = new MockParamSupportTag(); tag.setPageContext(createPageContext()); tag.setParent(parent); tag.setName("name2"); tag.setBodyContent(new MockBodyContent("value2", new MockHttpServletResponse())); action = tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, action); assertEquals("name2", parent.getParam().getName()); assertEquals("value2", parent.getParam().getValue()); }
@Test public void collectionOfColoursSelected() throws Exception { this.tag.setPath("otherColours"); this.tag.setValue("RED"); int result = this.tag.doStartTag(); assertEquals(Tag.SKIP_BODY, result); String output = getOutput(); // wrap the output so it is valid XML output = "<doc>" + output + "</doc>"; SAXReader reader = new SAXReader(); Document document = reader.read(new StringReader(output)); Element checkboxElement = (Element) document.getRootElement().elements().get(0); assertEquals("input", checkboxElement.getName()); assertEquals("checkbox", checkboxElement.attribute("type").getValue()); assertEquals("otherColours", checkboxElement.attribute("name").getValue()); assertEquals("checked", checkboxElement.attribute("checked").getValue()); }
@Test public void escapeBodyWithJavaScriptEscape() throws JspException { PageContext pc = createPageContext(); final StringBuffer result = new StringBuffer(); EscapeBodyTag tag = new EscapeBodyTag() { @Override protected String readBodyContent() { return "' test & text \\"; } @Override protected void writeBodyContent(String content) { result.append(content); } }; tag.setPageContext(pc); tag.setJavaScriptEscape(true); assertEquals(BodyTag.EVAL_BODY_BUFFERED, tag.doStartTag()); assertEquals(Tag.SKIP_BODY, tag.doAfterBody()); assertEquals("Correct content", "\\' test & text \\\\", result.toString()); }
/** * Figures out what to use as the value, and then finds the parent link and adds * the parameter. * @return EVAL_PAGE in all cases. */ public int doEndTag() throws JspException { Object valueToSet = value; // First figure out what value to send to the parent link tag if (value == null) { if (this.bodyContent == null) { valueToSet = ""; } else { valueToSet = this.bodyContent.getString(); } } // Find the parent link tag Tag parameterizable = this.parentTag; while (parameterizable != null && !(parameterizable instanceof ParameterizableTag)) { parameterizable = parameterizable.getParent(); } ((ParameterizableTag) parameterizable).addParameter(name, valueToSet); return EVAL_PAGE; }
public void doInitBody() throws JspException { //Test for doInitBody method. if ( "doInitBody".equalsIgnoreCase ( this.getAtt1() ) ) { TestString += this.getAtt1(); } // Test for getParent method in TagSupport if ( "getParent".equalsIgnoreCase ( this.getAtt2() ) ) { TagSupport ts = new TagSupport(); setParent( this ); Tag tt = getParent(); if ( tt == this ) { TestString = TestString + "Pass"; } else { TestString = TestString + "Fails"; } } }
@Test public void htmlEscapeTagWithContextParamFalse() throws JspException { PageContext pc = createPageContext(); MockServletContext sc = (MockServletContext) pc.getServletContext(); HtmlEscapeTag tag = new HtmlEscapeTag(); tag.setPageContext(pc); tag.doStartTag(); sc.addInitParameter(WebUtils.HTML_ESCAPE_CONTEXT_PARAM, "false"); assertTrue("Correct default", !tag.getRequestContext().isDefaultHtmlEscape()); tag.setDefaultHtmlEscape(true); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); assertTrue("Correctly enabled", tag.getRequestContext().isDefaultHtmlEscape()); tag.setDefaultHtmlEscape(false); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); assertTrue("Correctly disabled", !tag.getRequestContext().isDefaultHtmlEscape()); }
@Test public void messageTagWithCodeAndText() throws JspException { PageContext pc = createPageContext(); final StringBuffer message = new StringBuffer(); MessageTag tag = new MessageTag() { @Override protected void writeMessage(String msg) { message.append(msg); } }; tag.setPageContext(pc); tag.setCode("test"); tag.setText("testtext"); assertTrue("Correct doStartTag return value", tag.doStartTag() == Tag.EVAL_BODY_INCLUDE); assertEquals("Correct doEndTag return value", Tag.EVAL_PAGE, tag.doEndTag()); assertEquals("Correct message", "test message", (message.toString())); }
@Test public void withNestedOptions() throws Exception { this.tag.setPath("country"); int result = this.tag.doStartTag(); assertEquals(Tag.EVAL_BODY_INCLUDE, result); BindStatus value = (BindStatus) getPageContext().getAttribute(SelectTag.LIST_VALUE_PAGE_ATTRIBUTE); assertEquals("Selected country not exposed in page context", "UK", value.getValue()); result = this.tag.doEndTag(); assertEquals(Tag.EVAL_PAGE, result); this.tag.doFinally(); String output = getOutput(); assertTrue(output.startsWith("<select ")); assertTrue(output.endsWith("</select>")); assertContainsAttribute(output, "name", "country"); }