1 /* 2 * Copyright (c) 2003 The Visigoth Software Society. All rights 3 * reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. The end-user documentation included with the redistribution, if 18 * any, must include the following acknowledgement: 19 * "This product includes software developed by the 20 * Visigoth Software Society (http://www.visigoths.org/)." 21 * Alternately, this acknowledgement may appear in the software itself, 22 * if and wherever such third-party acknowledgements normally appear. 23 * 24 * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the 25 * project contributors may be used to endorse or promote products derived 26 * from this software without prior written permission. For written 27 * permission, please contact visigoths@visigoths.org. 28 * 29 * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth" 30 * nor may "FreeMarker" or "Visigoth" appear in their names 31 * without prior written permission of the Visigoth Software Society. 32 * 33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 36 * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR 37 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 40 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 41 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * ==================================================================== 46 * 47 * This software consists of voluntary contributions made by many 48 * individuals on behalf of the Visigoth Software Society. For more 49 * information on the Visigoth Software Society, please see 50 * http://www.visigoths.org/ 51 */ 52 53 package freemarker.debug; 54 55 import java.io.IOException; 56 import java.io.ObjectInputStream; 57 import java.io.ObjectOutputStream; 58 import java.net.InetAddress; 59 import java.net.Socket; 60 import java.rmi.RemoteException; 61 import java.rmi.server.RemoteObject; 62 import java.security.MessageDigest; 63 import java.util.Collection; 64 import java.util.List; 65 66 import freemarker.debug.impl.RmiDebuggerListenerImpl; 67 import freemarker.template.utility.UndeclaredThrowableException; 68 69 /** 70 * A utility class that allows you to connect to the FreeMarker debugger service 71 * running on a specific host and port. 72 * @author Attila Szegedi 73 * @version $Id: DebuggerClient.java,v 1.3.2.1 2006/11/27 07:54:19 szegedia Exp $ 74 */ 75 public class DebuggerClient 76 { 77 private DebuggerClient() 78 { 79 } 80 81 /** 82 * Connects to the FreeMarker debugger service running on a specific host 83 * and port. The Java VM to which the connection is made must have defined 84 * the system property <tt>freemarker.debug.password</tt> in order to enable 85 * the debugger service. Additionally, the <tt>freemarker.debug.port</tt> 86 * system property can be set to specify the port where the debugger service 87 * is listening. When not specified, it defaults to 88 * {@link Debugger#DEFAULT_PORT}. 89 * @param host the host address of the machine where the debugger service is 90 * running. 91 * @param port the port of the debugger service 92 * @param password the password required to connect to the debugger service 93 * @return Debugger a debugger object. null is returned in case incorrect 94 * password was supplied. 95 * @throws IOException if an exception occurs. 96 */ 97 public static Debugger getDebugger(InetAddress host, int port, String password) 98 throws 99 IOException 100 { 101 try 102 { 103 Socket s = new Socket(host, port); 104 try 105 { 106 ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream()); 107 ObjectInputStream in = new ObjectInputStream(s.getInputStream()); 108 int protocolVersion = in.readInt(); 109 if(protocolVersion > 220) 110 { 111 throw new IOException( 112 "Incompatible protocol version " + protocolVersion + 113 ". At most 220 was expected."); 114 } 115 byte[] challenge = (byte[])in.readObject(); 116 MessageDigest md = MessageDigest.getInstance("SHA"); 117 md.update(password.getBytes("UTF-8")); 118 md.update(challenge); 119 out.writeObject(md.digest()); 120 return new LocalDebuggerProxy((Debugger)in.readObject()); 121 //return (Debugger)in.readObject(); 122 } 123 finally 124 { 125 s.close(); 126 } 127 } 128 catch(IOException e) 129 { 130 throw e; 131 } 132 catch(Exception e) 133 { 134 throw new UndeclaredThrowableException(e); 135 } 136 } 137 138 private static class LocalDebuggerProxy implements Debugger 139 { 140 private final Debugger remoteDebugger; 141 142 LocalDebuggerProxy(Debugger remoteDebugger) 143 { 144 this.remoteDebugger = remoteDebugger; 145 } 146 147 public void addBreakpoint(Breakpoint breakpoint) throws RemoteException 148 { 149 remoteDebugger.addBreakpoint(breakpoint); 150 } 151 152 public Object addDebuggerListener(DebuggerListener listener) 153 throws RemoteException 154 { 155 if(listener instanceof RemoteObject) 156 { 157 return remoteDebugger.addDebuggerListener(listener); 158 } 159 else 160 { 161 RmiDebuggerListenerImpl remotableListener = 162 new RmiDebuggerListenerImpl(listener); 163 return remoteDebugger.addDebuggerListener(remotableListener); 164 } 165 } 166 167 public List getBreakpoints() throws RemoteException 168 { 169 return remoteDebugger.getBreakpoints(); 170 } 171 172 public List getBreakpoints(String templateName) throws RemoteException 173 { 174 return remoteDebugger.getBreakpoints(templateName); 175 } 176 177 public Collection getSuspendedEnvironments() throws RemoteException 178 { 179 return remoteDebugger.getSuspendedEnvironments(); 180 } 181 182 public void removeBreakpoint(Breakpoint breakpoint) throws RemoteException 183 { 184 remoteDebugger.removeBreakpoint(breakpoint); 185 } 186 187 public void removeBreakpoints(String templateName) throws RemoteException 188 { 189 remoteDebugger.removeBreakpoints(templateName); 190 } 191 192 public void removeBreakpoints() throws RemoteException 193 { 194 remoteDebugger.removeBreakpoints(); 195 } 196 197 public void removeDebuggerListener(Object id) throws RemoteException 198 { 199 remoteDebugger.removeDebuggerListener(id); 200 } 201 } 202 }