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