/* | |
* $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.FileManager; | |
import com.opensymphony.xwork2.FileManagerFactory; | |
import com.opensymphony.xwork2.conversion.impl.XWorkConverter; | |
import com.opensymphony.xwork2.inject.Container; | |
import com.opensymphony.xwork2.util.TextParser; | |
import com.opensymphony.xwork2.util.OgnlTextParser; | |
import com.opensymphony.xwork2.util.ValueStack; | |
import com.opensymphony.xwork2.util.finder.ClassLoaderInterface; | |
import com.opensymphony.xwork2.util.finder.ClassLoaderInterfaceDelegate; | |
import com.opensymphony.xwork2.util.fs.DefaultFileManager; | |
import com.sun.net.httpserver.HttpsParameters; | |
import junit.framework.TestCase; | |
import org.apache.commons.lang3.StringUtils; | |
import org.apache.struts2.dispatcher.HttpParameters; | |
import org.apache.struts2.views.util.DefaultUrlHelper; | |
import org.apache.struts2.views.util.UrlHelper; | |
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.HashSet; | |
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().trim()); | |
} | |
//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().trim()); | |
} | |
public void testAbsolutePath() throws Exception { | |
result.setLocation("/org/apache/struts2/simple0.jsp"); | |
result.execute(null); | |
assertEquals("hello", response.getContentAsString().trim()); | |
} | |
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 ActionContext.getContext().getParameters().get("username").getValue(); | |
} | |
}); | |
EasyMock.expect(request.getAttribute("something")).andReturn("somethingelse").anyTimes(); | |
EasyMock.replay(request); | |
ActionContext actionContext = new ActionContext(new HashMap<String, Object>()); | |
ActionContext.setContext(actionContext); | |
actionContext.setParameters(HttpParameters.create(params).build()); | |
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(); | |
DefaultFileManager fileManager = new DefaultFileManager(); | |
fileManager.setReloadingConfigs(false); | |
//mock container | |
Container container = EasyMock.createNiceMock(Container.class); | |
EasyMock.expect(container.getInstance(XWorkConverter.class)).andReturn(converter).anyTimes(); | |
TextParser parser = new OgnlTextParser(); | |
EasyMock.expect(container.getInstance(TextParser.class)).andReturn(parser).anyTimes(); | |
EasyMock.expect(container.getInstanceNames(FileManager.class)).andReturn(new HashSet<String>()).anyTimes(); | |
EasyMock.expect(container.getInstance(FileManager.class)).andReturn(fileManager).anyTimes(); | |
UrlHelper urlHelper = new DefaultUrlHelper(); | |
EasyMock.expect(container.getInstance(UrlHelper.class)).andReturn(urlHelper).anyTimes(); | |
FileManagerFactory fileManagerFactory = new DummyFileManagerFactory(); | |
EasyMock.expect(container.getInstance(FileManagerFactory.class)).andReturn(fileManagerFactory).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 DummyFileManagerFactory implements FileManagerFactory { | |
public void setReloadingConfigs(String reloadingConfigs) { | |
} | |
public FileManager getFileManager() { | |
return new DefaultFileManager(); | |
} | |
} | |
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 threads 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); | |
} | |
} |