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 }