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.annotations.Argument;
026    import org.crsh.cmdline.annotations.Command;
027    import org.crsh.cmdline.annotations.Option;
028    import org.crsh.cmdline.annotations.Usage;
029    import org.crsh.cmdline.matcher.CommandMatch;
030    import org.crsh.cmdline.matcher.InvocationContext;
031    import org.crsh.cmdline.matcher.Matcher;
032    import org.crsh.shell.impl.CRaSH;
033    import org.crsh.term.processor.Processor;
034    import org.crsh.term.BaseTerm;
035    import org.crsh.term.Term;
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    
045    /**
046     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
047     * @version $Revision$
048     */
049    public class Main {
050    
051      /** . */
052      private static Logger log = LoggerFactory.getLogger(Main.class);
053    
054      @Command
055      public void main(
056        @Option(names={"j","jar"})
057        @Usage("specify a file system path of a jar added to the class path")
058        List<String> jars,
059        @Option(names={"p","path"})
060        @Usage("specify a file system path of a dir added to the mount path")
061        List<String> paths,
062        @Argument(name = "pid")
063        @Usage("the optional JVM process id to attach to")
064        Integer pid) throws Exception {
065    
066        //
067        if (pid != null) {
068          // Standalone
069          URL url = Main.class.getProtectionDomain().getCodeSource().getLocation();
070          java.io.File f = new java.io.File(url.toURI());
071          log.info("Attaching to remote process " + pid);
072          VirtualMachine vm = VirtualMachine.attach("" + pid);
073    
074          //
075          TermIOServer server = new TermIOServer(new JLineIO(), 0);
076          int port = server.bind();
077          log.info("Callback server set on port " + port);
078    
079          // Build the options
080          StringBuilder sb = new StringBuilder();
081    
082          // Rewrite absolute path
083          if (paths != null) {
084            for (String path : paths) {
085              File file = new File(path);
086              if (file.exists()) {
087                sb.append("--path ").append(file.getAbsolutePath()).append(' ');
088              }
089            }
090          }
091    
092          // Rewrite absolute path
093          if (jars != null) {
094            for (String jar : jars) {
095              File file = new File(jar);
096              if (file.exists()) {
097                sb.append("--jar ").append(file.getAbsolutePath()).append(' ');
098              }
099            }
100          }
101    
102          // Append callback port
103          sb.append(port);
104    
105          //
106          String options = sb.toString();
107          log.info("Loading agent with command " + options);
108          vm.loadAgent(f.getCanonicalPath(), options);
109    
110          //
111          try {
112            server.accept();
113            while (server.execute()) {
114              //
115            }
116          } finally {
117            vm.detach();
118          }
119        } else {
120          final Bootstrap bootstrap = new Bootstrap(Thread.currentThread().getContextClassLoader());
121    
122          //
123          if (paths != null) {
124            for (String path : paths) {
125              File mount = new File(path);
126              bootstrap.addToMounts(mount);
127            }
128          }
129    
130          //
131          if (jars != null) {
132            for (String jar : jars) {
133              File jarFile = new File(jar);
134              bootstrap.addToClassPath(jarFile);
135            }
136          }
137    
138          // Register shutdown hook
139          Runtime.getRuntime().addShutdownHook(new Thread() {
140            @Override
141            public void run() {
142              // Should trigger some kind of run interruption
143            }
144          });
145    
146          // Do bootstrap
147          bootstrap.bootstrap();
148    
149          // Start crash for this command line
150          Term term = new BaseTerm(new JLineIO());
151          CRaSH crash = new CRaSH(bootstrap.getContext());
152          Processor processor = new Processor(term, crash.createSession());
153    
154          //
155          try {
156            processor.run();
157          }
158          finally {
159            bootstrap.shutdown();
160          }
161        }
162      }
163    
164      public static void main(String[] args) throws Exception {
165    
166        StringBuilder line = new StringBuilder();
167        for (int i = 0;i < args.length;i++) {
168          if (i  > 0) {
169            line.append(' ');
170          }
171          line.append(args[i]);
172        }
173    
174        //
175        ClassDescriptor<Main> c = CommandFactory.create(Main.class);
176        Matcher<Main> matcher = Matcher.createMatcher("main", c);
177        CommandMatch<Main, ?, ?> match = matcher.match(line.toString());
178        match.invoke(new InvocationContext(), new Main());
179      }
180    }