/******************************************************************************* * 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; } } }