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.shell.impl.command; 020 021import org.crsh.cli.impl.completion.CompletionMatch; 022import org.crsh.shell.impl.command.spi.CommandCreationException; 023import org.crsh.command.RuntimeContext; 024import org.crsh.shell.impl.command.spi.CommandInvoker; 025import org.crsh.shell.impl.command.spi.ShellCommand; 026import org.crsh.lang.script.ScriptRepl; 027import org.crsh.plugin.PluginContext; 028import org.crsh.repl.Repl; 029import org.crsh.repl.ReplSession; 030import org.crsh.shell.Shell; 031import org.crsh.shell.ShellProcess; 032import org.crsh.shell.ShellResponse; 033import org.crsh.repl.EvalResponse; 034import org.crsh.shell.impl.command.spi.CommandManager; 035 036import java.io.Closeable; 037import java.security.Principal; 038import java.util.HashMap; 039import java.util.Map; 040import java.util.logging.Level; 041import java.util.logging.Logger; 042 043public class CRaSHSession extends HashMap<String, Object> implements Shell, Closeable, RuntimeContext, ReplSession { 044 045 /** . */ 046 static final Logger log = Logger.getLogger(CRaSHSession.class.getName()); 047 048 /** . */ 049 static final Logger accessLog = Logger.getLogger("org.crsh.shell.access"); 050 051 /** . */ 052 public final CRaSH crash; 053 054 /** . */ 055 final Principal user; 056 057 /** . */ 058 private Repl repl = ScriptRepl.getInstance(); 059 060 CRaSHSession(final CRaSH crash, Principal user) { 061 // Set variable available to all scripts 062 put("crash", crash); 063 064 // 065 this.crash = crash; 066 this.user = user; 067 068 // 069 ClassLoader previous = setCRaSHLoader(); 070 try { 071 for (CommandManager manager : crash.activeManagers.values()) { 072 manager.init(this); 073 } 074 } 075 finally { 076 setPreviousLoader(previous); 077 } 078 } 079 080 /** 081 * Returns the current repl of this session. 082 * 083 * @return the current repl 084 */ 085 public Repl getRepl() { 086 return repl; 087 } 088 089 /** 090 * Set the current repl of this session. 091 * 092 * @param repl the new repl 093 * @throws NullPointerException if the repl is null 094 */ 095 public void setRepl(Repl repl) throws NullPointerException { 096 if (repl == null) { 097 throw new NullPointerException("No null repl accepted"); 098 } 099 this.repl = repl; 100 } 101 102 public Iterable<String> getCommandNames() { 103 return crash.getCommandNames(); 104 } 105 106 public ShellCommand<?> getCommand(String name) throws CommandCreationException { 107 return crash.getCommand(name); 108 } 109 110 public PluginContext getContext() { 111 return crash.context; 112 } 113 114 public Map<String, Object> getSession() { 115 return this; 116 } 117 118 public Map<String, Object> getAttributes() { 119 return crash.context.getAttributes(); 120 } 121 122 public void close() { 123 ClassLoader previous = setCRaSHLoader(); 124 try { 125 for (CommandManager manager : crash.activeManagers.values()) { 126 manager.destroy(this); 127 } 128 } 129 finally { 130 setPreviousLoader(previous); 131 } 132 } 133 134 // Shell implementation ********************************************************************************************** 135 136 public String getWelcome() { 137 ClassLoader previous = setCRaSHLoader(); 138 try { 139 CommandManager groovy = crash.activeManagers.get("groovy"); 140 if (groovy != null) { 141 return groovy.doCallBack(this, "welcome", ""); 142 } else { 143 return ""; 144 } 145 } 146 finally { 147 setPreviousLoader(previous); 148 } 149 } 150 151 public String getPrompt() { 152 ClassLoader previous = setCRaSHLoader(); 153 try { 154 CommandManager groovy = crash.activeManagers.get("groovy"); 155 if (groovy != null) { 156 return groovy.doCallBack(this, "prompt", "% "); 157 } else { 158 return "% "; 159 } 160 } 161 finally { 162 setPreviousLoader(previous); 163 } 164 } 165 166 public ShellProcess createProcess(String request) { 167 log.log(Level.FINE, "Invoking request " + request); 168 String trimmedRequest = request.trim(); 169 final StringBuilder msg = new StringBuilder(); 170 final ShellResponse response; 171 if ("bye".equals(trimmedRequest) || "exit".equals(trimmedRequest)) { 172 response = ShellResponse.close(); 173 } else { 174 EvalResponse r = repl.eval(this, request); 175 if (r instanceof EvalResponse.Response) { 176 EvalResponse.Response rr = (EvalResponse.Response)r; 177 response = rr.response; 178 } else { 179 final CommandInvoker<Void, ?> pipeLine = ((EvalResponse.Invoke)r).invoker; 180 return new CRaSHCommandProcess(this, request, pipeLine); 181 } 182 } 183 return new CRaSHResponseProcess(this, request, msg, response); 184 } 185 186 /** 187 * For now basic implementation 188 */ 189 public CompletionMatch complete(final String prefix) { 190 ClassLoader previous = setCRaSHLoader(); 191 try { 192 return repl.complete(this, prefix); 193 } 194 finally { 195 setPreviousLoader(previous); 196 } 197 } 198 199 ClassLoader setCRaSHLoader() { 200 Thread thread = Thread.currentThread(); 201 ClassLoader previous = thread.getContextClassLoader(); 202 thread.setContextClassLoader(crash.context.getLoader()); 203 return previous; 204 } 205 206 void setPreviousLoader(ClassLoader previous) { 207 Thread.currentThread().setContextClassLoader(previous); 208 } 209 210}