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.shell.impl.command; 020 021 import org.crsh.cli.impl.completion.CompletionMatch; 022 import org.crsh.lang.spi.Compiler; 023 import org.crsh.lang.spi.Language; 024 import org.crsh.lang.spi.Repl; 025 import org.crsh.lang.spi.ReplResponse; 026 import org.crsh.shell.impl.command.spi.CommandException; 027 import org.crsh.command.RuntimeContext; 028 import org.crsh.shell.impl.command.spi.CommandInvoker; 029 import org.crsh.shell.impl.command.spi.Command; 030 import org.crsh.lang.impl.script.ScriptRepl; 031 import org.crsh.plugin.PluginContext; 032 import org.crsh.shell.Shell; 033 import org.crsh.shell.ShellProcess; 034 import org.crsh.shell.ShellResponse; 035 036 import java.io.Closeable; 037 import java.security.Principal; 038 import java.util.HashMap; 039 import java.util.Map; 040 import java.util.logging.Level; 041 import java.util.logging.Logger; 042 043 class CRaSHSession extends HashMap<String, Object> implements Shell, Closeable, RuntimeContext, ShellSession { 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 (Language manager : crash.langs) { 072 manager.init(this); 073 } 074 } 075 finally { 076 setPreviousLoader(previous); 077 } 078 } 079 080 public Repl getRepl() { 081 return repl; 082 } 083 084 public void setRepl(Repl repl) throws NullPointerException { 085 if (repl == null) { 086 throw new NullPointerException("No null repl accepted"); 087 } 088 this.repl = repl; 089 } 090 091 public Iterable<Map.Entry<String, String>> getCommands() { 092 return crash.getCommands(); 093 } 094 095 public Command<?> getCommand(String name) throws CommandException { 096 return crash.getCommand(name); 097 } 098 099 public PluginContext getContext() { 100 return crash.context; 101 } 102 103 public Map<String, Object> getSession() { 104 return this; 105 } 106 107 public Map<String, Object> getAttributes() { 108 return crash.context.getAttributes(); 109 } 110 111 public void close() { 112 ClassLoader previous = setCRaSHLoader(); 113 try { 114 for (Language manager : crash.langs) { 115 manager.destroy(this); 116 } 117 } 118 finally { 119 setPreviousLoader(previous); 120 } 121 } 122 123 // Shell implementation ********************************************************************************************** 124 125 public String getWelcome() { 126 ClassLoader previous = setCRaSHLoader(); 127 try { 128 Compiler groovy = crash.scriptResolver.getCompiler("groovy"); 129 if (groovy != null) { 130 return groovy.doCallBack(this, "welcome", ""); 131 } else { 132 return ""; 133 } 134 } 135 finally { 136 setPreviousLoader(previous); 137 } 138 } 139 140 public String getPrompt() { 141 ClassLoader previous = setCRaSHLoader(); 142 try { 143 Compiler groovy = crash.scriptResolver.getCompiler("groovy"); 144 if (groovy != null) { 145 return groovy.doCallBack(this, "prompt", "% "); 146 } else { 147 return "% "; 148 } 149 } 150 finally { 151 setPreviousLoader(previous); 152 } 153 } 154 155 public ShellProcess createProcess(String request) { 156 log.log(Level.FINE, "Invoking request " + request); 157 String trimmedRequest = request.trim(); 158 final StringBuilder msg = new StringBuilder(); 159 final ShellResponse response; 160 if ("bye".equals(trimmedRequest) || "exit".equals(trimmedRequest)) { 161 response = ShellResponse.close(); 162 } else { 163 ReplResponse r = repl.eval(this, request); 164 if (r instanceof ReplResponse.Response) { 165 ReplResponse.Response rr = (ReplResponse.Response)r; 166 response = rr.response; 167 } else { 168 final CommandInvoker<Void, ?> pipeLine = ((ReplResponse.Invoke)r).invoker; 169 return new CRaSHCommandProcess(this, request, pipeLine); 170 } 171 } 172 return new CRaSHResponseProcess(this, request, msg, response); 173 } 174 175 /** 176 * For now basic implementation 177 */ 178 public CompletionMatch complete(final String prefix) { 179 ClassLoader previous = setCRaSHLoader(); 180 try { 181 return repl.complete(this, prefix); 182 } 183 finally { 184 setPreviousLoader(previous); 185 } 186 } 187 188 ClassLoader setCRaSHLoader() { 189 Thread thread = Thread.currentThread(); 190 ClassLoader previous = thread.getContextClassLoader(); 191 thread.setContextClassLoader(crash.context.getLoader()); 192 return previous; 193 } 194 195 void setPreviousLoader(ClassLoader previous) { 196 Thread.currentThread().setContextClassLoader(previous); 197 } 198 199 }