001 /* 002 * Copyright (C) 2010 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.standalone; 021 022 import com.sun.tools.attach.VirtualMachine; 023 import org.crsh.cmdline.ClassDescriptor; 024 import org.crsh.cmdline.CommandFactory; 025 import org.crsh.cmdline.IntrospectionException; 026 import org.crsh.cmdline.annotations.Argument; 027 import org.crsh.cmdline.annotations.Command; 028 import org.crsh.cmdline.annotations.Option; 029 import org.crsh.cmdline.annotations.Usage; 030 import org.crsh.cmdline.matcher.CommandMatch; 031 import org.crsh.cmdline.matcher.InvocationContext; 032 import org.crsh.cmdline.matcher.Matcher; 033 import org.crsh.term.BaseTerm; 034 import org.crsh.term.Term; 035 import org.crsh.term.processor.Processor; 036 import org.crsh.term.spi.jline.JLineIO; 037 import org.crsh.term.spi.net.TermIOServer; 038 import org.slf4j.Logger; 039 import org.slf4j.LoggerFactory; 040 041 import java.io.File; 042 import java.net.*; 043 import java.util.List; 044 import java.util.Properties; 045 046 /** 047 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> 048 * @version $Revision$ 049 */ 050 public class CRaSH { 051 052 /** . */ 053 private static Logger log = LoggerFactory.getLogger(CRaSH.class); 054 055 /** . */ 056 private final ClassDescriptor<CRaSH> descriptor; 057 058 public CRaSH() throws IntrospectionException { 059 this.descriptor = CommandFactory.create(CRaSH.class); 060 } 061 062 @Command 063 public void main( 064 @Option(names = {"h","help"}) 065 @Usage("display standalone mode help") 066 Boolean help, 067 @Option(names={"j","jar"}) 068 @Usage("specify a file system path of a jar added to the class path") 069 List<String> jars, 070 @Option(names={"c","cmd"}) 071 @Usage("specify a file system path of a dir added to the command path") 072 List<String> cmds, 073 @Option(names={"conf"}) 074 @Usage("specify a file system path of a dir added to the configuration path") 075 List<String> confs, 076 @Option(names={"p","property"}) 077 @Usage("specify a configuration property of the form a=b") 078 List<String> properties, 079 @Argument(name = "pid") 080 @Usage("the optional JVM process id to attach to") 081 Integer pid) throws Exception { 082 083 // 084 if (Boolean.TRUE.equals(help)) { 085 descriptor.printUsage(System.out); 086 } else if (pid != null) { 087 088 // Standalone 089 URL url = CRaSH.class.getProtectionDomain().getCodeSource().getLocation(); 090 java.io.File f = new java.io.File(url.toURI()); 091 log.info("Attaching to remote process " + pid); 092 VirtualMachine vm = VirtualMachine.attach("" + pid); 093 094 // 095 TermIOServer server = new TermIOServer(new JLineIO(), 0); 096 int port = server.bind(); 097 log.info("Callback server set on port " + port); 098 099 // Build the options 100 StringBuilder sb = new StringBuilder(); 101 102 // Rewrite canonical path 103 if (cmds != null) { 104 for (String cmd : cmds) { 105 File cmdPath = new File(cmd); 106 if (cmdPath.exists()) { 107 sb.append("--cmd ").append(cmdPath.getCanonicalPath()).append(' '); 108 } 109 } 110 } 111 112 // Rewrite canonical path 113 if (confs != null) { 114 for (String conf : confs) { 115 File confPath = new File(conf); 116 if (confPath.exists()) { 117 sb.append("--conf ").append(confPath.getCanonicalPath()).append(' '); 118 } 119 } 120 } 121 122 // Rewrite canonical path 123 if (jars != null) { 124 for (String jar : jars) { 125 File jarPath = new File(jar); 126 if (jarPath.exists()) { 127 sb.append("--jar ").append(jarPath.getCanonicalPath()).append(' '); 128 } 129 } 130 } 131 132 // Propagate canonical config 133 if (properties != null) { 134 for (String property : properties) { 135 sb.append("--property ").append(property).append(' '); 136 } 137 } 138 139 // Append callback port 140 sb.append(port); 141 142 // 143 String options = sb.toString(); 144 log.info("Loading agent with command " + options); 145 vm.loadAgent(f.getCanonicalPath(), options); 146 147 // 148 try { 149 server.accept(); 150 while (server.execute()) { 151 // 152 } 153 } finally { 154 vm.detach(); 155 } 156 } else { 157 final Bootstrap bootstrap = new Bootstrap(Thread.currentThread().getContextClassLoader()); 158 159 // 160 if (cmds != null) { 161 for (String cmd : cmds) { 162 File cmdPath = new File(cmd); 163 bootstrap.addCmdPath(cmdPath); 164 } 165 } 166 167 // 168 if (confs != null) { 169 for (String conf : confs) { 170 File confPath = new File(conf); 171 bootstrap.addCmdPath(confPath); 172 } 173 } 174 175 // 176 if (jars != null) { 177 for (String jar : jars) { 178 File jarPath = new File(jar); 179 bootstrap.addJarPath(jarPath); 180 } 181 } 182 183 // 184 if (properties != null) { 185 Properties config = new Properties(); 186 for (String property : properties) { 187 int index = property.indexOf('='); 188 if (index == -1) { 189 config.setProperty(property, ""); 190 } else { 191 config.setProperty(property.substring(0, index), property.substring(index + 1)); 192 } 193 } 194 bootstrap.setConfig(config); 195 } 196 197 // Register shutdown hook 198 Runtime.getRuntime().addShutdownHook(new Thread() { 199 @Override 200 public void run() { 201 // Should trigger some kind of run interruption 202 } 203 }); 204 205 // Do bootstrap 206 bootstrap.bootstrap(); 207 208 // Start crash for this command line 209 Term term = new BaseTerm(new JLineIO()); 210 org.crsh.shell.impl.CRaSH crash = new org.crsh.shell.impl.CRaSH(bootstrap.getContext()); 211 Processor processor = new Processor(term, crash.createSession()); 212 213 // 214 try { 215 processor.run(); 216 } 217 finally { 218 bootstrap.shutdown(); 219 } 220 } 221 } 222 223 public static void main(String[] args) throws Exception { 224 225 StringBuilder line = new StringBuilder(); 226 for (int i = 0;i < args.length;i++) { 227 if (i > 0) { 228 line.append(' '); 229 } 230 line.append(args[i]); 231 } 232 233 // 234 CRaSH main = new CRaSH(); 235 Matcher<CRaSH> matcher = Matcher.createMatcher("main", main.descriptor); 236 CommandMatch<CRaSH, ?, ?> match = matcher.match(line.toString()); 237 match.invoke(new InvocationContext(), new CRaSH()); 238 } 239 }