/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
import com.opensymphony.xwork2.inject.Container;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
import com.opensymphony.xwork2.util.finder.ClassLoaderInterfaceDelegate;
import junit.framework.TestCase;
import org.apache.commons.lang.StringUtils;
import org.easymock.EasyMock;
import org.easymock.IAnswer;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class EmbeddedJSPResultTest extends TestCase {
private HttpServletRequest request;
private MockHttpServletResponse response;
private MockServletContext context;
private EmbeddedJSPResult result;
public void testScriptlet() throws Exception {
result.setLocation("org/apache/struts2/scriptlet.jsp");
result.execute(null);
assertEquals("Saynotoscriptlets", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testEmbedded() throws Exception {
//the jsp is inside jsps.jar
result.setLocation("dir/all.jsp");
result.execute(null);
assertEquals("helloJGWhoamI?XXXXXXXXXXXYThissessionisnotsecure.", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testFilesAreReadOnlyOnce() throws Exception {
//make sure that files are not read multiple times
String jsp = "org/apache/struts2/dont-use.jsp";
CountingClassLoaderInterface classLoaderInterface = new CountingClassLoaderInterface(this.getClass().getClassLoader());
context.setAttribute(ClassLoaderInterface.CLASS_LOADER_INTERFACE, classLoaderInterface);
result.setLocation(jsp);
result.execute(null);
Integer counter0 = classLoaderInterface.counters.get(jsp);
assertNotNull(counter0);
result.execute(null);
Integer counter1 = classLoaderInterface.counters.get(jsp);
assertNotNull(counter1);
assertEquals(counter0, counter1);
}
public void testEmbeddedAbsolutePath() throws Exception {
//the jsp is inside jsps.jar
result.setLocation("/dir/all.jsp");
result.execute(null);
assertEquals("helloJGWhoamI?XXXXXXXXXXXYThissessionisnotsecure.", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testSimple() throws Exception {
result.setLocation("org/apache/struts2/simple0.jsp");
result.execute(null);
assertEquals("hello", response.getContentAsString());
}
//ok i give up..i don't know why this doesn't work from maven
/* public void testKeyInContext() throws Exception {
result.setLocation("org/apache/struts2/scriptlet.jsp");
result.execute(null);
String key = JspApplicationContextImpl.class.getName() + "@" + this.getClass().getClassLoader().hashCode();
assertNotNull(context.getAttribute(key));
}*/
public void testEL() throws Exception {
result.setLocation("org/apache/struts2/el.jsp");
result.execute(null);
assertEquals("somethingelseText", response.getContentAsString());
}
public void tesAbsolutePatht() throws Exception {
result.setLocation("/org/apache/struts2/simple0.jsp");
result.execute(null);
assertEquals("hello", response.getContentAsString());
}
public void testTag0() throws Exception {
result.setLocation("org/apache/struts2/tag0.jsp");
result.execute(null);
assertEquals("Thissessionisnotsecure.OtherText", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testIncludeSimple() throws Exception {
result.setLocation("org/apache/struts2/includes0.jsp");
result.execute(null);
assertEquals("helloTest", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testIncludeSimpleWithDirective() throws Exception {
result.setLocation("org/apache/struts2/includes3.jsp");
result.execute(null);
assertEquals("helloTest", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testIncludeWithSubdir() throws Exception {
result.setLocation("org/apache/struts2/includes1.jsp");
result.execute(null);
assertEquals("subTest", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testIncludeWithParam() throws Exception {
result.setLocation("org/apache/struts2/includes2.jsp");
result.execute(null);
assertEquals("JGTest", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testBroken0() throws Exception {
try {
result.setLocation("org/apache/struts2/broken0.jsp");
result.execute(null);
fail("should have failed with broken jsp");
} catch (IllegalStateException ex) {
//ok
}
}
public void testJSTL() throws Exception {
result.setLocation("org/apache/struts2/jstl.jsp");
result.execute(null);
assertEquals("XXXXXXXXXXXY", StringUtils.deleteWhitespace(response.getContentAsString()));
}
public void testCachedInstances() throws InterruptedException {
ServletCache cache = new ServletCache();
Servlet servlet1 = cache.get("org/apache/struts2/simple0.jsp");
Servlet servlet2 = cache.get("org/apache/struts2/simple0.jsp");
assertSame(servlet1, servlet2);
}
public void testCacheInstanceWithManyThreads() throws BrokenBarrierException, InterruptedException {
//start a bunch of thread at the same time using CyclicBarrier and hit the cache
//then wait for all the threads to end and check that they all got a reference to the same object
//and the cache size should be 1
DummyServletCache cache = new DummyServletCache();
int numThreads = 70;
CyclicBarrier startBarrier = new CyclicBarrier(numThreads + 1);
CyclicBarrier endBarrier = new CyclicBarrier(numThreads + 1);
List<ServletGetRunnable> runnables = new ArrayList<ServletGetRunnable>(numThreads);
//create the threads
for (int i = 0; i < numThreads; i++) {
ServletGetRunnable runnable = new ServletGetRunnable(cache, startBarrier, endBarrier, ActionContext.getContext());
Thread thread = new Thread(runnable);
runnables.add(runnable);
thread.start();
}
startBarrier.await();
endBarrier.await();
Object servlet = cache.get("org/apache/struts2/simple0.jsp");
assertEquals(1, cache.size());
for (ServletGetRunnable runnable : runnables) {
assertSame(servlet, runnable.getObject());
}
}
public void testBeans() throws Exception {
result.setLocation("org/apache/struts2/beans.jsp");
result.execute(null);
assertEquals("WhoamI?", StringUtils.deleteWhitespace(response.getContentAsString()));
}
@Override
protected void setUp() throws Exception {
super.setUp();
result = new EmbeddedJSPResult();
request = EasyMock.createNiceMock(HttpServletRequest.class);
response = new MockHttpServletResponse();
context = new MockServletContext();
final Map params = new HashMap();
HttpSession session = EasyMock.createNiceMock(HttpSession.class);
EasyMock.replay(session);
EasyMock.expect(request.getSession()).andReturn(session).anyTimes();
EasyMock.expect(request.getParameterMap()).andReturn(params).anyTimes();
EasyMock.expect(request.getParameter("username")).andAnswer(new IAnswer<String>() {
public String answer() throws Throwable {
return ((String[]) params.get("username"))[0];
}
});
EasyMock.expect(request.getAttribute("something")).andReturn("somethingelse").anyTimes();
EasyMock.replay(request);
ActionContext actionContext = new ActionContext(new HashMap<String, Object>());
ActionContext.setContext(actionContext);
actionContext.setParameters(params);
ServletActionContext.setRequest(request);
ServletActionContext.setResponse(response);
ServletActionContext.setServletContext(context);
//mock value stack
Map stackContext = new HashMap();
ValueStack valueStack = EasyMock.createNiceMock(ValueStack.class);
EasyMock.expect(valueStack.getContext()).andReturn(stackContext).anyTimes();
EasyMock.replay(valueStack);
//mock converter
XWorkConverter converter = new DummyConverter();
//mock container
Container container = EasyMock.createNiceMock(Container.class);
EasyMock.expect(container.getInstance(XWorkConverter.class)).andReturn(converter).anyTimes();
EasyMock.replay(container);
stackContext.put(ActionContext.CONTAINER, container);
actionContext.setContainer(container);
actionContext.setValueStack(valueStack);
}
}
//converter has a protected default constructor...meh
class DummyConverter extends XWorkConverter {
}
class DummyServletCache extends ServletCache {
public int size() {
return cache.size();
}
}
class ServletGetRunnable implements Runnable {
private ServletCache servletCache;
private Object object;
private CyclicBarrier startBarrier;
private ActionContext actionContext;
private CyclicBarrier endBarrier;
ServletGetRunnable(ServletCache servletCache, CyclicBarrier startBarrier, CyclicBarrier endBarrier, ActionContext actionContext) {
this.servletCache = servletCache;
this.startBarrier = startBarrier;
this.endBarrier = endBarrier;
this.actionContext = actionContext;
}
public void run() {
ActionContext.setContext(actionContext);
//wait to start all therads at once..or try at least
try {
startBarrier.await();
object = servletCache.get("org/apache/struts2/simple0.jsp");
for (int i = 0; i < 10; i++) {
Object object2 = servletCache.get("org/apache/struts2/simple0.jsp");
if (object2 != object)
throw new RuntimeException("got different object from cache");
}
endBarrier.await();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Object getObject() {
return object;
}
}
class CountingClassLoaderInterface extends ClassLoaderInterfaceDelegate {
public Map<String, Integer> counters = new HashMap<String, Integer>();
public CountingClassLoaderInterface(ClassLoader classLoader) {
super(classLoader);
}
@Override
public InputStream getResourceAsStream(String name) {
Integer counter = counters.get(name);
counter = counter == null ? 1 : counter + 1;
counters.put(name, counter);
return super.getResourceAsStream(name);
}
}