blob: e93e028588b8090e7b9b7c92f454e61696d14717 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2008 Oracle Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Oracle Corporation - initial API and implementation
*******************************************************************************/
package instrument;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Writer;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingQueue;
import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.eclipse.jst.jsf.common.runtime.internal.debug.ComponentTreeMessage;
import org.eclipse.jst.jsf.common.runtime.internal.debug.JSFMonitorMessage;
import org.eclipse.jst.jsf.common.runtime.internal.debug.MonitorMessageFactory;
import org.eclipse.jst.jsf.common.runtime.internal.debug.RenderAttribute;
import org.eclipse.jst.jsf.common.runtime.internal.debug.RenderNode;
import org.eclipse.jst.jsf.common.runtime.internal.model.component.ComponentInfo;
/**
* @author cbateman
*
*/
public class PhaseListener1 implements PhaseListener
{
SocketClient _socketClient;
ResponseWriter _savedRW;
LoggingResponseWriter _injectRW;
/**
*
*/
private static final long serialVersionUID = 6564874625827591775L;
public PhaseListener1()
{
System.out.println("Initialized PhaseListener: "+this);
_socketClient = new SocketClient(3702);
Thread thread = new Thread(_socketClient);
thread.start();
}
public void afterPhase(PhaseEvent event) {
if(PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
{
System.out.printf("afterPhase: %s, for view id: %s\n",event.getPhaseId(),event.getFacesContext().getViewRoot().getViewId());
dumpComponentTree(event.getFacesContext());
if (_savedRW != null)
{
event.getFacesContext().setResponseWriter(_savedRW);
}
if (_injectRW != null)
{
dumpNode(_injectRW._rootComponentNode, "");
}
}
}
private void dumpNode(RenderNode node, String prefix)
{
System.out.printf("%s%s for component %s\n", prefix, node.getRenderedNodeName(), node.getComponentId());
for (final Iterator it = node.getChildren().iterator();it.hasNext();)
{
RenderNode child = (RenderNode) it.next();
dumpNode(child, prefix+"\t");
}
}
public void beforePhase(PhaseEvent event) {
if (PhaseId.RENDER_RESPONSE.equals(event.getPhaseId()))
{
FacesContext facesContext = event.getFacesContext();
RenderKitFactory renderFactory =
(RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
RenderKit renderKit = renderFactory.getRenderKit(facesContext,
facesContext.getViewRoot().getRenderKitId());
_savedRW = facesContext.getResponseWriter();
try
{
Writer writer = ((ServletResponse) facesContext.getExternalContext().getResponse()).getWriter();
String charEncoding = ((ServletRequest)facesContext.getExternalContext().getRequest()).getCharacterEncoding();
ResponseWriter responseWriter = renderKit.createResponseWriter
(writer,
null /*Default: get the allowed content-types from the accept-header*/,
charEncoding);
_injectRW = new LoggingResponseWriter(responseWriter);
facesContext.setResponseWriter(_injectRW);
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
// System.out.printf("beforePhase: %s, for view id: %s\n",event.getPhaseId(),event.getFacesContext().getViewRoot().getViewId());
// dumpComponentTree(event.getFacesContext());
}
public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
private void dumpComponentTree(final FacesContext facesContext)
{
final UIViewRoot root = facesContext.getViewRoot();
if (root != null)
{
final String viewId = root.getViewId();
final ComponentInfo rootComponent = MyMonitorMessageFactory.buildComponentTree(root,false);
ComponentTreeMessage message =
MonitorMessageFactory.createTreeMessage(viewId, rootComponent, _injectRW._rootComponentNode);
_socketClient.put(message);
}
}
private static class SocketClient implements Runnable
{
private final int _port;
private LinkedBlockingQueue<JSFMonitorMessage> _queue =
new LinkedBlockingQueue<JSFMonitorMessage>();
SocketClient(final int port)
{
_port = port;
}
public void run()
{
JSFMonitorMessage buffer = null;
try
{
while ((buffer = _queue.take()) != null)
{
Socket socket = null;
try
{
socket = new Socket("127.0.0.1", _port);
ObjectOutputStream stream = new ObjectOutputStream(socket.getOutputStream());
stream.writeObject(buffer);
// PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
// writer.println(buffer);
// writer.flush();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
finally
{
if (socket != null && !socket.isClosed())
{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public void put(JSFMonitorMessage message)
{
_queue.add(message);
}
}
private static class LoggingResponseWriter extends ResponseWriter
{
private final ResponseWriter _wrapWriter;
private final Stack/*<RenderNode>*/ _parentStack;
private RenderNode _curNode;
private RenderNode _rootComponentNode;
// map component id to the root rendernode rendered for it
private Map _componentToHtml;
LoggingResponseWriter(ResponseWriter wrapWriter)
{
_wrapWriter = wrapWriter;
_parentStack = new Stack();
_componentToHtml = new HashMap/*<String,RenderNode>*/();
}
public ResponseWriter cloneWithWriter(Writer writer) {
return _wrapWriter.cloneWithWriter(writer);
}
public void endDocument() throws IOException {
_wrapWriter.endDocument();
}
public void endElement(String element) throws IOException {
_curNode = (RenderNode) _parentStack.pop();
_wrapWriter.endElement(element);
}
public void flush() throws IOException {
_wrapWriter.flush();
}
public String getCharacterEncoding() {
return _wrapWriter.getCharacterEncoding();
}
public String getContentType() {
return _wrapWriter.getContentType();
}
public void startDocument() throws IOException {
_rootComponentNode = new RenderNode(null, null);
_wrapWriter.startDocument();
}
public void startElement(String elementName, UIComponent component)
throws IOException
{
String componentId = null;
if (component != null)
{
componentId = component.getId();
}
RenderNode oldNode = _curNode;
// push the curNode. Pushing null indicates the root of the document
_parentStack.push(oldNode);
_curNode = new RenderNode(componentId, elementName);
// note that assumption here is that the first html element
// we see corresponding to a component is the root of its
// html tree. This may not be true if a component renders
// more than one root element or if the output is generated
// any thing but pre-order (parent first) tranversal of the
// component tree. TODO: this algorithm needs refining
if (!_componentToHtml.containsKey(componentId))
{
_componentToHtml.put(componentId, _curNode);
}
// if the current node isn't null, then append this new element
if (oldNode != null)
{
oldNode.getChildren().add(_curNode);
}
// otherwise, we are at the doc root, so append there instead
else
{
_rootComponentNode.getChildren().add(_curNode);
}
// do the normal write
_wrapWriter.startElement(elementName, component);
}
public void writeAttribute(String name, Object value, String componentPropertyName)
throws IOException {
System.out.printf("%s: [%s,%s]\n", name, value.toString(), componentPropertyName);
final RenderAttribute attribute =
new RenderAttribute(name, value.toString(), componentPropertyName);
if (_curNode != null)
{
_curNode.getRenderedAttributes().add(attribute);
}
_wrapWriter.writeAttribute(name, value, componentPropertyName);
}
public void writeComment(Object obj) throws IOException {
_wrapWriter.writeComment(obj);
}
public void writeText(Object arg0, String arg1) throws IOException {
_wrapWriter.writeText(arg0, arg1);
}
public void writeText(char[] arg0, int arg1, int arg2)
throws IOException {
_wrapWriter.writeText(arg0, arg1, arg2);
}
public void writeURIAttribute(String arg0, Object arg1, String arg2)
throws IOException {
_wrapWriter.writeURIAttribute(arg0, arg1, arg2);
}
public void close() throws IOException {
_wrapWriter.close();
}
public void write(char[] cbuf, int off, int len) throws IOException {
_wrapWriter.write(cbuf, off, len);
}
public ResponseWriter getWrapWriter() {
return _wrapWriter;
}
}
}