001/* 002 * Copyright (C) 2012 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 */ 019package org.crsh.standalone; 020 021import org.crsh.cli.Usage; 022import org.crsh.cli.descriptor.CommandDescriptor; 023import org.crsh.cli.Argument; 024import org.crsh.cli.Command; 025import org.crsh.cli.Option; 026import org.crsh.cli.impl.lang.CommandFactory; 027import org.crsh.cli.impl.invocation.InvocationMatch; 028import org.crsh.cli.impl.invocation.InvocationMatcher; 029import org.crsh.cli.impl.lang.Instance; 030import org.crsh.cli.impl.lang.Util; 031import org.crsh.shell.Shell; 032import org.crsh.shell.ShellFactory; 033import org.crsh.shell.impl.remoting.RemoteClient; 034import org.crsh.vfs.Path; 035 036import java.io.File; 037import java.lang.instrument.Instrumentation; 038import java.util.Collections; 039import java.util.List; 040import java.util.Map; 041import java.util.Properties; 042import java.util.logging.Level; 043import java.util.logging.Logger; 044 045public class Agent { 046 047 /** . */ 048 private static Logger log = Logger.getLogger(Agent.class.getName()); 049 050 public static void agentmain(final String agentArgs, final Instrumentation inst) throws Exception { 051 log.log(Level.INFO, "CRaSH agent loaded"); 052 053 // 054 Thread t = new Thread() { 055 @Override 056 public void run() { 057 try { 058 CommandDescriptor<Instance<Agent>> c = CommandFactory.DEFAULT.create(Agent.class); 059 InvocationMatcher<Instance<Agent>> matcher = c.matcher(); 060 InvocationMatch<Instance<Agent>> match = matcher.parse(agentArgs); 061 match.invoke(Util.wrap(new Agent(inst))); 062 } catch (Exception e) { 063 e.printStackTrace(); 064 } 065 } 066 }; 067 068 // 069 t.start(); 070 log.log(Level.INFO, "Spawned CRaSH thread " + t.getId() + " for further processing"); 071 } 072 073 /** . */ 074 private final Instrumentation instrumentation; 075 076 public Agent(Instrumentation instrumentation) { 077 this.instrumentation = instrumentation; 078 } 079 080 @Command 081 public void main( 082 @Option(names={"c","cmd"}) 083 @Usage("adds a dir to the command path") 084 List<String> cmds, 085 @Option(names={"conf"}) 086 @Usage("adds a dir to the conf path") 087 List<String> confs, 088 @Option(names={"p","property"}) 089 @Usage("set a property of the form a=b") 090 List<String> properties, 091 @Option(names = {"cmd-mode"}) 092 @Usage("the cmd mode (read or copy), copy mode requires at least one cmd path to be specified") 093 ResourceMode cmdMode, 094 @Option(names = {"conf-mode"}) 095 @Usage("the conf mode (read of copy), copy mode requires at least one conf path to be specified") 096 ResourceMode confMode, 097 @Argument(name = "port") 098 Integer port) throws Exception { 099 100 // 101 boolean copyCmd = cmdMode != ResourceMode.read && cmds != null && cmds.size() > 0; 102 boolean copyConf = confMode != ResourceMode.read && confs != null && confs.size() > 0; 103 104 // 105 Bootstrap bootstrap = new Bootstrap(Thread.currentThread().getContextClassLoader()); 106 107 // 108 if (!copyCmd) { 109 bootstrap.addToCmdPath(Path.get("/crash/commands/")); 110 } 111 if (cmds != null) { 112 for (String cmd : cmds) { 113 File cmdPath = new File(cmd); 114 bootstrap.addToCmdPath(cmdPath); 115 } 116 } 117 118 119 // 120 if (!copyConf) { 121 bootstrap.addToConfPath(Path.get("/crash/")); 122 } 123 if (confs != null) { 124 for (String conf : confs) { 125 File confPath = new File(conf); 126 bootstrap.addToConfPath(confPath); 127 } 128 } 129 130 // 131 if (properties != null) { 132 Properties config = new Properties(); 133 for (String property : properties) { 134 int index = property.indexOf('='); 135 if (index == -1) { 136 config.setProperty(property, ""); 137 } else { 138 config.setProperty(property.substring(0, index), property.substring(index + 1)); 139 } 140 } 141 bootstrap.setConfig(config); 142 } 143 144 // Set the instrumentation available as an attribute 145 Map<String, Object> attributes = Collections.<String, Object>singletonMap("instrumentation", instrumentation); 146 bootstrap.setAttributes(attributes); 147 148 // Do bootstrap 149 bootstrap.bootstrap(); 150 151 // 152 if (port != null) { 153 try { 154 ShellFactory factory = bootstrap.getContext().getPlugin(ShellFactory.class); 155 Shell shell = factory.create(null); 156 RemoteClient client = new RemoteClient(port, shell); 157 log.log(Level.INFO, "Callback back remote on port " + port); 158 client.connect(); 159 client.getRunnable().run(); 160 } 161 finally { 162 bootstrap.shutdown(); 163 } 164 } 165 } 166}