blob: 6530aa3443fdb0ad444d134dca63d4f0a6b363cb [file] [log] [blame]
Felix Meschbergerefb2d082008-08-19 13:18:47 +00001/*
Richard S. Hall59aef192009-04-25 14:50:37 +00002 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Felix Meschbergerefb2d082008-08-19 13:18:47 +000017package org.apache.felix.shell.remote;
18
Felix Meschbergerefb2d082008-08-19 13:18:47 +000019import java.io.BufferedReader;
20import java.io.IOException;
21import java.io.PrintStream;
22import java.net.Socket;
23
Felix Meschbergerd7c324d2008-08-19 14:10:48 +000024import org.apache.felix.shell.ShellService;
25
Felix Meschbergerefb2d082008-08-19 13:18:47 +000026/**
27 * Implements the shell.
Felix Meschberger73bf1232009-02-02 08:28:42 +000028 * <p>
29 * This class is instantiated by the {@link Listener} thread to handle a single
30 * remote connection in its own thread. The connection handler thread either
31 * terminates on request by the remote end or by the Remote Shell bundle being
32 * stopped. In the latter case, the {@link #terminate()} method is called, which
33 * closes the Socket used to handle the remote console. This causes a
34 * <code>SocketException</code> in the handler thread reading from the socket
35 * which in turn causes the {@link #run()} method to terminate and thus to
36 * end the handler thread.
Felix Meschbergerefb2d082008-08-19 13:18:47 +000037 */
38class Shell implements Runnable
39{
Richard S. Hall55900ec2009-04-25 16:57:58 +000040 private final Listener m_owner;
41 private final Socket m_socket;
42 private final AtomicInteger m_useCounter;
43 private volatile TerminalPrintStream m_out;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000044
Richard S. Hall59aef192009-04-25 14:50:37 +000045 public Shell(Listener owner, Socket s, AtomicInteger counter)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000046 {
Felix Meschberger73bf1232009-02-02 08:28:42 +000047 m_owner = owner;
Richard S. Hall59aef192009-04-25 14:50:37 +000048 m_socket = s;
49 m_useCounter = counter;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000050 }//constructor
51
Felix Meschberger73bf1232009-02-02 08:28:42 +000052 void terminate()
53 {
54 // called by Listener.deactivate() to terminate this session
Richard S. Hall59aef192009-04-25 14:50:37 +000055 exit("\r\nFelix Remote Shell Console Terminating");
Felix Meschberger73bf1232009-02-02 08:28:42 +000056 }//terminate
Richard S. Hall59aef192009-04-25 14:50:37 +000057
Felix Meschbergerefb2d082008-08-19 13:18:47 +000058 /**
59 * Runs the shell.
60 */
61 public void run()
62 {
Richard S. Hall59aef192009-04-25 14:50:37 +000063 m_owner.registerConnection(this);
64
Felix Meschbergerefb2d082008-08-19 13:18:47 +000065 try
66 {
Richard S. Hall55900ec2009-04-25 16:57:58 +000067 m_out = new TerminalPrintStream(
68 m_owner.getServices(), m_socket.getOutputStream());
69 BufferedReader in = new BufferedReader(
70 new TerminalReader(m_socket.getInputStream(), m_out));
Felix Meschbergerefb2d082008-08-19 13:18:47 +000071 ReentrantLock lock = new ReentrantLock();
72
73 // Print welcome banner.
Richard S. Hall55900ec2009-04-25 16:57:58 +000074 m_out.println();
75 m_out.println("Felix Remote Shell Console:");
76 m_out.println("============================");
77 m_out.println("");
Felix Meschbergerefb2d082008-08-19 13:18:47 +000078
79 do
80 {
Felix Meschbergerefb2d082008-08-19 13:18:47 +000081 String line = "";
82 try
83 {
Richard S. Hall55900ec2009-04-25 16:57:58 +000084 m_out.print("-> ");
Felix Meschbergerefb2d082008-08-19 13:18:47 +000085 line = in.readLine();
86 //make sure to capture end of stream
Richard S. Hall59aef192009-04-25 14:50:37 +000087 if (line == null)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000088 {
Richard S. Hall55900ec2009-04-25 16:57:58 +000089 m_out.println("exit");
Felix Meschbergerefb2d082008-08-19 13:18:47 +000090 return;
91 }
92 }
Richard S. Hall59aef192009-04-25 14:50:37 +000093 catch (Exception ex)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000094 {
Felix Meschbergerefb2d082008-08-19 13:18:47 +000095 return;
96 }
97
98 line = line.trim();
Richard S. Hall59aef192009-04-25 14:50:37 +000099 if (line.equalsIgnoreCase("exit") || line.equalsIgnoreCase("disconnect"))
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000100 {
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000101 return;
102 }
103
Richard S. Hall55900ec2009-04-25 16:57:58 +0000104 ShellService shs = m_owner.getServices().getFelixShellService(ServiceMediator.NO_WAIT);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000105 try
106 {
107 lock.acquire();
Richard S. Hall55900ec2009-04-25 16:57:58 +0000108 shs.executeCommand(line, m_out, m_out);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000109 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000110 catch (Exception ex)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000111 {
Richard S. Hall55900ec2009-04-25 16:57:58 +0000112 m_owner.getServices().error("Shell::run()", ex);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000113 }
114 finally
115 {
116 lock.release();
117 }
118 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000119 while (true);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000120 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000121 catch (IOException ex)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000122 {
Richard S. Hall55900ec2009-04-25 16:57:58 +0000123 m_owner.getServices().error("Shell::run()", ex);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000124 }
Felix Meschberger73bf1232009-02-02 08:28:42 +0000125 finally
126 {
127 // no need to clean up in/out, since exit does it all
Richard S. Hall59aef192009-04-25 14:50:37 +0000128 exit(null);
Felix Meschberger73bf1232009-02-02 08:28:42 +0000129 }
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000130 }//run
131
Felix Meschberger73bf1232009-02-02 08:28:42 +0000132 private void exit(String message)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000133 {
Felix Meschberger73bf1232009-02-02 08:28:42 +0000134 // farewell message
Richard S. Hall55900ec2009-04-25 16:57:58 +0000135 if (message != null)
Felix Meschberger73bf1232009-02-02 08:28:42 +0000136 {
Richard S. Hall55900ec2009-04-25 16:57:58 +0000137 m_out.println(message);
Felix Meschberger73bf1232009-02-02 08:28:42 +0000138 }
Richard S. Hall55900ec2009-04-25 16:57:58 +0000139 m_out.println("Good Bye!");
140 m_out.close();
Felix Meschberger73bf1232009-02-02 08:28:42 +0000141
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000142 try
143 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000144 m_socket.close();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000145 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000146 catch (IOException ex)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000147 {
Richard S. Hall55900ec2009-04-25 16:57:58 +0000148 m_owner.getServices().error("Shell::exit()", ex);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000149 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000150 m_owner.unregisterConnection(this);
151 m_useCounter.decrement();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000152 }//exit
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000153}//class Shell