/**
* Copyright (c) 2009-2011 VMware, Inc. All Rights Reserved.
*
* Licensed 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 com.springsource.insight.plugin.springweb.remoting;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.HttpConnection;
import org.mortbay.jetty.Request;
import org.mortbay.jetty.Server;
import org.springframework.remoting.httpinvoker.AbstractHttpInvokerRequestExecutor;
import org.springframework.remoting.httpinvoker.HttpInvokerClientConfiguration;
import org.springframework.remoting.httpinvoker.SimpleHttpInvokerRequestExecutor;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationResult;
import com.springsource.insight.intercept.InterceptConfiguration;
import com.springsource.insight.intercept.color.Color;
import com.springsource.insight.intercept.operation.Operation;
import com.springsource.insight.intercept.topology.ExternalResourceDescriptor;
import com.springsource.insight.intercept.trace.FrameBuilder;
import com.springsource.insight.util.ArrayUtil;
import com.springsource.insight.util.ClassUtil;
import com.springsource.insight.util.StringUtil;
/**
*
*/
public class SimpleHttpInvokerRequestExecutorAspectTest
extends HttpInvokerRequestOperationCollectionTestSupport {
private static final Log logger = LogFactory.getLog(SimpleHttpInvokerRequestExecutorAspectTest.class);
private static Server SERVER;
public SimpleHttpInvokerRequestExecutorAspectTest() {
super();
}
@BeforeClass
public static void startEmbeddedServer() throws Exception {
SERVER = new Server(TEST_PORT);
SERVER.setHandler(new TestHandler());
logger.info("Starting embedded server on port " + TEST_PORT);
SERVER.start();
logger.info("Started embedded server on port " + TEST_PORT);
}
@AfterClass
public static void stopEmbeddedServer() throws Exception {
if (SERVER != null) {
logger.info("Stopping embedded server");
SERVER.stop();
logger.info("Server stopped");
}
}
@Test
public void testSimpleHttpInvokerRequestExecutor() throws Exception {
RemoteInvocation invocation =
new RemoteInvocation("testSimpleHttpInvokerRequestExecutor", new Class[]{Long.class}, new Object[]{Long.valueOf(System.nanoTime())});
TestingSimpleHttpInvokerRequestExecutor executor = new TestingSimpleHttpInvokerRequestExecutor(invocation.getMethodName());
HttpInvokerClientConfiguration config = createMockConfiguration(executor.getColor(), ArrayUtil.EMPTY_STRINGS);
RemoteInvocationResult result = executor.executeRequest(config, invocation);
Object value = result.getValue();
assertNotNull("No result value", value);
assertTrue("Bad result value type: " + value.getClass().getSimpleName(), value instanceof RemoteInvocation);
RemoteInvocation resultValue = (RemoteInvocation) value;
assertEquals("Mismatched result method", invocation.getMethodName(), resultValue.getMethodName());
assertArrayEquals("Mismatched result signature", invocation.getParameterTypes(), resultValue.getParameterTypes());
assertArrayEquals("Mismatched result arguments", invocation.getArguments(), resultValue.getArguments());
Operation op = assertRemotingOperation(config);
assertEquals("Mismatched request method", executor.getMethod(), op.get("method", String.class));
ExternalResourceDescriptor desc = assertExternalResource(op);
assertNotNull("No external resource generated", desc);
}
@Override
public SimpleHttpInvokerRequestExecutorAspect getAspect() {
return SimpleHttpInvokerRequestExecutorAspect.aspectOf();
}
static class TestingSimpleHttpInvokerRequestExecutor extends SimpleHttpInvokerRequestExecutor {
private final String color;
TestingSimpleHttpInvokerRequestExecutor(String colorValue) {
if (StringUtil.isEmpty(colorValue)) {
throw new IllegalArgumentException("No color value specified");
}
color = colorValue;
setBeanClassLoader(ClassUtil.getDefaultClassLoader(getClass()));
}
String getColor() {
return color;
}
String getMethod() {
return HTTP_METHOD_POST;
}
@Override
protected void prepareConnection(HttpURLConnection connection, int contentLength) throws IOException {
InterceptConfiguration config = InterceptConfiguration.getInstance();
FrameBuilder builder = config.getFrameBuilder();
@SuppressWarnings("unchecked")
List<Color> colors = builder.getHint(Color.TOKEN_NAME, List.class);
if (colors == null) {
colors = new ArrayList<Color>();
builder.setHint(Color.TOKEN_NAME, colors);
}
colors.add(new Color(null, getColor(), getClass().getSimpleName(), "prepareConnection"));
super.prepareConnection(connection, contentLength);
}
}
static class TestHandler implements Handler {
private Server server;
private boolean started;
protected TestHandler() {
super();
}
public void addLifeCycleListener(Listener listener) {
// ignored
}
public void removeLifeCycleListener(Listener listener) {
// ignored
}
public void stop() throws Exception {
if (!started) {
throw new IllegalStateException("Not started");
}
started = false;
}
public void start() throws Exception {
if (started) {
throw new IllegalStateException("Double start");
}
started = true;
}
public boolean isStopping() {
return true;
}
public boolean isStopped() {
return !started;
}
public boolean isStarting() {
return true;
}
public boolean isStarted() {
return started;
}
public boolean isRunning() {
return started;
}
public boolean isFailed() {
return false;
}
public Server getServer() {
return this.server;
}
public void setServer(Server s) {
this.server = s;
}
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
throws IOException, ServletException {
ObjectInputStream reqStream = new ObjectInputStream(request.getInputStream());
RemoteInvocation invocation;
try {
invocation = (RemoteInvocation) reqStream.readObject();
} catch (ClassNotFoundException e) {
throw new ServletException("Failed to load invocation class: " + e.getMessage(), e);
} finally {
reqStream.close();
}
System.out.println("Invocation: " + invocation + " - args=" + Arrays.toString(invocation.getArguments()));
assertEquals("Mismatched target value", "/" + invocation.getMethodName(), target);
String color = request.getHeader(Color.TOKEN_NAME);
assertFalse("No color provided", StringUtil.isEmpty(color));
RemoteInvocationResult result = new RemoteInvocationResult(invocation);
response.setStatus(HttpServletResponse.SC_OK);
response.setContentType(AbstractHttpInvokerRequestExecutor.CONTENT_TYPE_SERIALIZED_OBJECT);
ObjectOutputStream rspStream = new ObjectOutputStream(response.getOutputStream());
try {
rspStream.writeObject(result);
} finally {
rspStream.close();
}
Request baseRequest = (request instanceof Request)
? (Request) request
: HttpConnection.getCurrentConnection().getRequest();
baseRequest.setHandled(true);
}
public void destroy() {
if (this.server != null)
this.server = null;
}
}
}