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.Delimiter; 026 import org.crsh.cmdline.IntrospectionException; 027 import org.crsh.cmdline.annotations.Argument; 028 import org.crsh.cmdline.annotations.Command; 029 import org.crsh.cmdline.annotations.Option; 030 import org.crsh.cmdline.annotations.Usage; 031 import org.crsh.cmdline.matcher.CommandMatch; 032 import org.crsh.cmdline.matcher.InvocationContext; 033 import org.crsh.cmdline.matcher.Matcher; 034 import org.crsh.term.BaseTerm; 035 import org.crsh.term.Term; 036 import org.crsh.term.processor.Processor; 037 import org.crsh.term.spi.jline.JLineIO; 038 import org.crsh.term.spi.net.TermIOServer; 039 import org.slf4j.Logger; 040 import org.slf4j.LoggerFactory; 041 042 import java.io.File; 043 import java.net.*; 044 import java.util.List; 045 import java.util.Properties; 046 047 /** 048 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> 049 * @version $Revision$ 050 */ 051 public class CRaSH { 052 053 /** . */ 054 private static Logger log = LoggerFactory.getLogger(CRaSH.class); 055 056 /** . */ 057 private final ClassDescriptor<CRaSH> descriptor; 058 059 public CRaSH() throws IntrospectionException { 060 this.descriptor = CommandFactory.create(CRaSH.class); 061 } 062 063 @Command 064 public void main( 065 @Option(names = {"h","help"}) 066 @Usage("display standalone mode help") 067 Boolean help, 068 @Option(names={"j","jar"}) 069 @Usage("specify a file system path of a jar added to the class path") 070 List<String> jars, 071 @Option(names={"c","cmd"}) 072 @Usage("specify a file system path of a dir added to the command path") 073 List<String> cmds, 074 @Option(names={"conf"}) 075 @Usage("specify a file system path of a dir added to the configuration path") 076 List<String> confs, 077 @Option(names={"p","property"}) 078 @Usage("specify a configuration property of the form a=b") 079 List<String> properties, 080 @Argument(name = "pid") 081 @Usage("the optional JVM process id to attach to") 082 Integer pid) throws Exception { 083 084 // 085 if (Boolean.TRUE.equals(help)) { 086 descriptor.printUsage(System.out); 087 } else if (pid != null) { 088 089 // Standalone 090 URL url = CRaSH.class.getProtectionDomain().getCodeSource().getLocation(); 091 java.io.File f = new java.io.File(url.toURI()); 092 log.info("Attaching to remote process " + pid); 093 VirtualMachine vm = VirtualMachine.attach("" + pid); 094 095 // 096 TermIOServer server = new TermIOServer(new JLineIO(), 0); 097 int port = server.bind(); 098 log.info("Callback server set on port " + port); 099 100 // Build the options 101 StringBuilder sb = new StringBuilder(); 102 103 // Rewrite canonical path 104 if (cmds != null) { 105 for (String cmd : cmds) { 106 File cmdPath = new File(cmd); 107 if (cmdPath.exists()) { 108 sb.append("--cmd "); 109 Delimiter.EMPTY.escape(cmdPath.getCanonicalPath(), sb); 110 sb.append(' '); 111 } 112 } 113 } 114 115 // Rewrite canonical path 116 if (confs != null) { 117 for (String conf : confs) { 118 File confPath = new File(conf); 119 if (confPath.exists()) { 120 sb.append("--conf "); 121 Delimiter.EMPTY.escape(confPath.getCanonicalPath(), sb); 122 sb.append(' '); 123 } 124 } 125 } 126 127 // Rewrite canonical path 128 if (jars != null) { 129 for (String jar : jars) { 130 File jarPath = new File(jar); 131 if (jarPath.exists()) { 132 sb.append("--jar "); 133 Delimiter.EMPTY.escape(jarPath.getCanonicalPath(), sb); 134 sb.append(' '); 135 } 136 } 137 } 138 139 // Propagate canonical config 140 if (properties != null) { 141 for (String property : properties) { 142 sb.append("--property "); 143 Delimiter.EMPTY.escape(property, sb); 144 sb.append(' '); 145 } 146 } 147 148 // Append callback port 149 sb.append(port); 150 151 // 152 String options = sb.toString(); 153 log.info("Loading agent with command " + options); 154 vm.loadAgent(f.getCanonicalPath(), options); 155 156 // 157 try { 158 server.accept(); 159 while (server.execute()) { 160 // 161 } 162 } finally { 163 vm.detach(); 164 } 165 } else { 166 final Bootstrap bootstrap = new Bootstrap(Thread.currentThread().getContextClassLoader()); 167 168 // 169 if (cmds != null) { 170 for (String cmd : cmds) { 171 File cmdPath = new File(cmd); 172 bootstrap.addCmdPath(cmdPath); 173 } 174 } 175 176 // 177 if (confs != null) { 178 for (String conf : confs) { 179 File confPath = new File(conf); 180 bootstrap.addCmdPath(confPath); 181 } 182 } 183 184 // 185 if (jars != null) { 186 for (String jar : jars) { 187 File jarPath = new File(jar); 188 bootstrap.addJarPath(jarPath); 189 } 190 } 191 192 // 193 if (properties != null) { 194 Properties config = new Properties(); 195 for (String property : properties) { 196 int index = property.indexOf('='); 197 if (index == -1) { 198 config.setProperty(property, ""); 199 } else { 200 config.setProperty(property.substring(0, index), property.substring(index + 1)); 201 } 202 } 203 bootstrap.setConfig(config); 204 } 205 206 // Register shutdown hook 207 Runtime.getRuntime().addShutdownHook(new Thread() { 208 @Override 209 public void run() { 210 // Should trigger some kind of run interruption 211 } 212 }); 213 214 // Do bootstrap 215 bootstrap.bootstrap(); 216 217 // Start crash for this command line 218 Term term = new BaseTerm(new JLineIO()); 219 org.crsh.shell.impl.CRaSH crash = new org.crsh.shell.impl.CRaSH(bootstrap.getContext()); 220 Processor processor = new Processor(term, crash.createSession(null)); 221 222 // 223 try { 224 processor.run(); 225 } 226 finally { 227 bootstrap.shutdown(); 228 } 229 } 230 } 231 232 public static void main(String[] args) throws Exception { 233 234 StringBuilder line = new StringBuilder(); 235 for (int i = 0;i < args.length;i++) { 236 if (i > 0) { 237 line.append(' '); 238 } 239 Delimiter.EMPTY.escape(args[i], line); 240 } 241 242 // 243 CRaSH main = new CRaSH(); 244 Matcher<CRaSH> matcher = Matcher.createMatcher("main", main.descriptor); 245 CommandMatch<CRaSH, ?, ?> match = matcher.match(line.toString()); 246 match.invoke(new InvocationContext(), new CRaSH()); 247 } 248 }