blob: f70639626ed1c3c93750f4d342f214b88328b44f [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;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000021import java.net.Socket;
22
Felix Meschbergerd7c324d2008-08-19 14:10:48 +000023import org.apache.felix.shell.ShellService;
Richard S. Hallfd9c8832010-09-20 19:28:38 +000024import org.apache.felix.service.command.CommandProcessor;
25import org.apache.felix.service.command.CommandSession;
Felix Meschbergerd7c324d2008-08-19 14:10:48 +000026
Felix Meschbergerefb2d082008-08-19 13:18:47 +000027/**
28 * Implements the shell.
Felix Meschberger73bf1232009-02-02 08:28:42 +000029 * <p>
30 * This class is instantiated by the {@link Listener} thread to handle a single
31 * remote connection in its own thread. The connection handler thread either
32 * terminates on request by the remote end or by the Remote Shell bundle being
33 * stopped. In the latter case, the {@link #terminate()} method is called, which
34 * closes the Socket used to handle the remote console. This causes a
35 * <code>SocketException</code> in the handler thread reading from the socket
36 * which in turn causes the {@link #run()} method to terminate and thus to
37 * end the handler thread.
Felix Meschbergerefb2d082008-08-19 13:18:47 +000038 */
39class Shell implements Runnable
40{
Richard S. Hall55900ec2009-04-25 16:57:58 +000041 private final Listener m_owner;
42 private final Socket m_socket;
43 private final AtomicInteger m_useCounter;
44 private volatile TerminalPrintStream m_out;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000045
Richard S. Hall59aef192009-04-25 14:50:37 +000046 public Shell(Listener owner, Socket s, AtomicInteger counter)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000047 {
Felix Meschberger73bf1232009-02-02 08:28:42 +000048 m_owner = owner;
Richard S. Hall59aef192009-04-25 14:50:37 +000049 m_socket = s;
50 m_useCounter = counter;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000051 }//constructor
52
Felix Meschberger73bf1232009-02-02 08:28:42 +000053 void terminate()
54 {
55 // called by Listener.deactivate() to terminate this session
Richard S. Hall59aef192009-04-25 14:50:37 +000056 exit("\r\nFelix Remote Shell Console Terminating");
Felix Meschberger73bf1232009-02-02 08:28:42 +000057 }//terminate
Richard S. Hall59aef192009-04-25 14:50:37 +000058
Felix Meschbergerefb2d082008-08-19 13:18:47 +000059 /**
60 * Runs the shell.
61 */
62 public void run()
63 {
Richard S. Hall59aef192009-04-25 14:50:37 +000064 m_owner.registerConnection(this);
65
Richard S. Hall6f5381e2010-08-17 14:49:44 +000066 String msg = null;
67
Felix Meschbergerefb2d082008-08-19 13:18:47 +000068 try
69 {
Richard S. Hall55900ec2009-04-25 16:57:58 +000070 m_out = new TerminalPrintStream(
71 m_owner.getServices(), m_socket.getOutputStream());
Felix Meschbergerefb2d082008-08-19 13:18:47 +000072
Richard S. Hall6f5381e2010-08-17 14:49:44 +000073 Object obj = null;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000074
Richard S. Hall6f5381e2010-08-17 14:49:44 +000075 if ((obj = m_owner.getServices().getCommandProcessor(ServiceMediator.NO_WAIT))
76 != null)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000077 {
Richard S. Hall6f5381e2010-08-17 14:49:44 +000078 CommandProcessor cp = (CommandProcessor) obj;
79 CommandSession session =
80 cp.createSession(m_socket.getInputStream(), m_out, m_out);
81 startGogoShell(session);
Felix Meschbergerefb2d082008-08-19 13:18:47 +000082 }
Richard S. Hall6f5381e2010-08-17 14:49:44 +000083 else if ((obj = m_owner.getServices().getShellService(ServiceMediator.NO_WAIT))
84 != null)
85 {
86 startFelixShell();
87 }
88 else
89 {
90 msg = "No shell services available...exiting.";
91 }
Felix Meschbergerefb2d082008-08-19 13:18:47 +000092 }
Richard S. Hall59aef192009-04-25 14:50:37 +000093 catch (IOException ex)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000094 {
Richard S. Hall55900ec2009-04-25 16:57:58 +000095 m_owner.getServices().error("Shell::run()", ex);
Felix Meschbergerefb2d082008-08-19 13:18:47 +000096 }
Felix Meschberger73bf1232009-02-02 08:28:42 +000097 finally
98 {
99 // no need to clean up in/out, since exit does it all
Richard S. Hall6f5381e2010-08-17 14:49:44 +0000100 exit(msg);
Felix Meschberger73bf1232009-02-02 08:28:42 +0000101 }
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000102 }//run
103
Richard S. Hall6f5381e2010-08-17 14:49:44 +0000104 private void startGogoShell(CommandSession session)
105 {
106 try
107 {
108 session.execute("gosh --login --noshutdown");
109 }
110 catch (Exception e)
111 {
112 e.printStackTrace();
113 }
114 finally
115 {
116 session.close();
117 }
118 }
119
120 private void startFelixShell() throws IOException
121 {
122 BufferedReader in = new BufferedReader(
123 new TerminalReader(m_socket.getInputStream(), m_out));
124 ReentrantLock lock = new ReentrantLock();
125
126 // Print welcome banner.
127 m_out.println();
128 m_out.println("Felix Remote Shell Console:");
129 m_out.println("============================");
130 m_out.println("");
131
132 do
133 {
134 String line = "";
135 try
136 {
137 m_out.print("-> ");
138 line = in.readLine();
139 //make sure to capture end of stream
140 if (line == null)
141 {
142 m_out.println("exit");
143 return;
144 }
145 }
146 catch (Exception ex)
147 {
148 return;
149 }
150
151 line = line.trim();
152 if (line.equalsIgnoreCase("exit") || line.equalsIgnoreCase("disconnect"))
153 {
154 return;
155 }
156
157 ShellService shs = (ShellService)
158 m_owner.getServices().getShellService(ServiceMediator.NO_WAIT);
159 try
160 {
161 lock.acquire();
162 shs.executeCommand(line, m_out, m_out);
163 }
164 catch (Exception ex)
165 {
166 m_owner.getServices().error("Shell::run()", ex);
167 }
168 finally
169 {
170 lock.release();
171 }
172 }
173 while (true);
174 }
175
Felix Meschberger73bf1232009-02-02 08:28:42 +0000176 private void exit(String message)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000177 {
Felix Meschberger73bf1232009-02-02 08:28:42 +0000178 // farewell message
Richard S. Hall55900ec2009-04-25 16:57:58 +0000179 if (message != null)
Felix Meschberger73bf1232009-02-02 08:28:42 +0000180 {
Richard S. Hall55900ec2009-04-25 16:57:58 +0000181 m_out.println(message);
Felix Meschberger73bf1232009-02-02 08:28:42 +0000182 }
Richard S. Hall55900ec2009-04-25 16:57:58 +0000183 m_out.println("Good Bye!");
184 m_out.close();
Felix Meschberger73bf1232009-02-02 08:28:42 +0000185
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000186 try
187 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000188 m_socket.close();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000189 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000190 catch (IOException ex)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000191 {
Richard S. Hall55900ec2009-04-25 16:57:58 +0000192 m_owner.getServices().error("Shell::exit()", ex);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000193 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000194 m_owner.unregisterConnection(this);
195 m_useCounter.decrement();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000196 }//exit
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000197}//class Shell