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.shell.ShellProcess;
022    import org.crsh.shell.ShellProcessContext;
023    import org.crsh.shell.ShellResponse;
024    
025    import java.util.logging.Level;
026    
027    abstract class CRaSHProcess implements ShellProcess {
028    
029      /** . */
030      protected final CRaSHSession crash;
031    
032      /** . */
033      protected final String request;
034    
035      /** . */
036      private volatile Thread thread;
037    
038      /** . */
039      private volatile boolean cancelled;
040    
041      protected CRaSHProcess(CRaSHSession crash, String request) {
042        this.crash = crash;
043        this.request = request;
044      }
045    
046      public void execute(ShellProcessContext processContext) {
047        ClassLoader previous = crash.setCRaSHLoader();
048        try {
049          ShellResponse resp;
050          thread = Thread.currentThread();
051    
052          //
053          String userName = crash.user != null ? crash.user.getName() : "unauthenticated";
054          CRaSHSession.accessLog.log(Level.FINE, "User " + userName + " executes " + request);
055    
056          //
057          try {
058            try {
059              resp = doInvoke(processContext);
060              if (Thread.interrupted() || cancelled) {
061                throw new InterruptedException("like a goto");
062              }
063            }
064            catch (InterruptedException e) {
065              resp = ShellResponse.cancelled();
066            }
067          } catch (Throwable t) {
068            resp = ShellResponse.internalError("Unexpected error when executing process", t);
069          } finally {
070            thread = null;
071          }
072    
073          //
074          processContext.end(resp);
075    
076          //
077          if (resp instanceof ShellResponse.Error) {
078            ShellResponse.Error error = (ShellResponse.Error)resp;
079            Throwable t = error.getThrowable();
080            if (t != null) {
081              CRaSHSession.log.log(Level.SEVERE, "Error while evaluating request '" + request + "' " + error.getMessage(), t);
082            } else {
083              CRaSHSession.log.log(Level.SEVERE, "Error while evaluating request '" + request + "' " + error.getMessage());
084            }
085          }
086        }
087        finally {
088          crash.setPreviousLoader(previous);
089        }
090      }
091    
092      abstract ShellResponse doInvoke(ShellProcessContext context) throws InterruptedException;
093    
094      public void cancel() {
095        ClassLoader previous = crash.setCRaSHLoader();
096        try {
097          Thread t = thread;
098          if (t != null) {
099            t.interrupt();
100          }
101          cancelled = true;
102        }
103        finally {
104          crash.setPreviousLoader(previous);
105        }
106      }
107    }