Package org.eclipse.osgi.framework.internal.core

Source Code of org.eclipse.osgi.framework.internal.core.FrameworkConsole$ConsoleSocketGetter

/*******************************************************************************
* Copyright (c) 2003, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.osgi.framework.internal.core;

import java.io.*;
import java.net.*;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;

/**
* This class starts OSGi with a console for development use.
*
* FrameworkConsole provides a printStackTrace method to print Exceptions and their
* nested Exceptions.
*/
public class FrameworkConsole implements Runnable {
  /** The stream to receive commands on  */
  protected BufferedReader in;
  /** The stream to write command results to */
  protected PrintWriter out;
  /** The current bundle context */
  protected final org.osgi.framework.BundleContext context;
  /** The current osgi instance */
  protected final OSGi osgi;
  /** The command line arguments passed at launch time*/
  protected final String[] args;
  /** The OSGi Command Provider */
  protected final CommandProvider osgicp;
  /** A tracker containing the service object of all registered command providers */
  protected final ServiceTracker cptracker;

  /** Default code page which must be supported by all JVMs */
  static final String defaultEncoding = "iso8859-1"; //$NON-NLS-1$
  /** The current setting for code page */
  static final String encoding = FrameworkProperties.getProperty("osgi.console.encoding", FrameworkProperties.getProperty("file.encoding", defaultEncoding)); //$NON-NLS-1$ //$NON-NLS-2$

  /** set to true if accepting commands from port */
  protected final boolean useSocketStream;
  protected boolean disconnect = false;
  protected final int port;
  protected ConsoleSocketGetter scsg = null;
  protected Socket s;
  boolean blockOnready = FrameworkProperties.getProperty("osgi.dev") != null || FrameworkProperties.getProperty("osgi.console.blockOnReady") != null; //$NON-NLS-1$ //$NON-NLS-2$
  volatile boolean shutdown = false;

  /**
   Constructor for FrameworkConsole.
   It creates a service tracker to track CommandProvider registrations.
   The console InputStream is set to System.in and the console PrintStream is set to System.out.
   @param osgi - an instance of an osgi framework
   @param args - any arguments passed on the command line when Launcher is started.
   */
  public FrameworkConsole(OSGi osgi, String[] args) {
    this(osgi, args, 0, false);
  }

  /**
   Constructor for FrameworkConsole.
   It creates a service tracker to track CommandProvider registrations.
   The console InputStream is set to System.in and the console PrintStream is set to System.out.
   @param osgi - an instance of an osgi framework
   @param args - any arguments passed on the command line when Launcher is started.
   */
  public FrameworkConsole(OSGi osgi, int port, String[] args) {
    this(osgi, args, port, true);
  }

  private FrameworkConsole(OSGi osgi, String[] args, int port, boolean useSocketStream) {
    this.args = args;
    this.osgi = osgi;
    this.useSocketStream = useSocketStream;
    this.port = port;
    this.context = osgi.getBundleContext();

    // set up a service tracker to track CommandProvider registrations
    this.cptracker = new ServiceTracker(context, CommandProvider.class.getName(), null);
    this.cptracker.open();

    // register the OSGi command provider
    this.osgicp = new FrameworkCommandProvider(osgi).intialize();
  }

  /**
   *  Open streams for system.in and system.out
   */
  private void getDefaultStreams() {
    InputStream is = new FilterInputStream(System.in) {
      public void close() throws IOException {
        // We don't want to close System.in
      }
    };
    in = createBufferedReader(is);

    OutputStream os = new FilterOutputStream(System.out) {
      public void close() throws IOException {
        // We don't want to close System.out
      }
    };
    out = createPrintWriter(os);
    disconnect = false;
  }

  /**
   *  Open a socket and create input and output streams
   *
   * @param port number to listen on
   */
  private boolean getSocketStream() {
    try {
      System.out.println(NLS.bind(ConsoleMsg.CONSOLE_LISTENING_ON_PORT, String.valueOf(port)));
      synchronized (this) {
        if (scsg == null)
          scsg = new ConsoleSocketGetter(new ServerSocket(port));
        scsg.setAcceptConnections(true);
      }
      // get socket outside of sync block
      Socket temp = scsg.getSocket();
      if (temp == null)
        return false;
      synchronized (this) {
        s = temp;
        in = createBufferedReader(s.getInputStream());
        out = createPrintWriter(s.getOutputStream());
        disconnect = false;
      }
      return true;
    } catch (UnknownHostException uhe) {
      uhe.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return false;
  }

  /**
   * Return a BufferedReader from an InputStream.  Handle encoding.
   *
   * @param _in An InputStream to wrap with a BufferedReader
   * @return a BufferedReader
   */
  private BufferedReader createBufferedReader(InputStream _in) {
    BufferedReader reader;
    try {
      reader = new BufferedReader(new InputStreamReader(_in, encoding));
    } catch (UnsupportedEncodingException uee) {
      // if the encoding is not supported by the jvm, punt and use whatever encodiing there is
      reader = new BufferedReader(new InputStreamReader(_in));
    }
    return reader;
  }

  /**
   * Return a PrintWriter from an OutputStream.  Handle encoding.
   *
   * @param _out An OutputStream to wrap with a PrintWriter
   * @return a PrintWriter
   */
  PrintWriter createPrintWriter(OutputStream _out) {
    PrintWriter writer;
    try {
      writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(_out, encoding)), true);
    } catch (UnsupportedEncodingException uee) {
      // if the encoding is not supported by the jvm, punt and use whatever encodiing there is
      writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(_out)), true);
    }
    return writer;
  }

  /**
   *  Return the current output PrintWriter
   * @return The currently active PrintWriter
   */
  public PrintWriter getWriter() {
    return out;
  }

  /**
   *  Return the current input BufferedReader
   * @return The currently active BufferedReader
   */
  public BufferedReader getReader() {
    return in;
  }

  /**
   *  Return if the SocketSteam (telnet to the console) is being used
   * @return Return if the SocketSteam is being used
   */
  public boolean getUseSocketStream() {
    return useSocketStream;
  }

  /**
   * Begin doing the active part of the class' code. Starts up the console.
   */
  public void run() {
    // always grab the default streams
    getDefaultStreams();
    try {
      // process any arguments from the command line
      console(args);
    } catch (IOException e) {
      e.printStackTrace(out);
    }
    while (!shutdown) {
      if (useSocketStream && !getSocketStream())
        return;
      try {
        console();
      } catch (IOException e) {
        if (!shutdown)
          e.printStackTrace(out);
        if (!useSocketStream) {
          // better just return; the standard console has failed us.  Don't want to get in an endless loop (bug 212313)
          return;
        }
      }
    }
  }

  /**
   * Command Line Interface for OSGi. The method processes the initial commands
   * and then reads and processes commands from the console InputStream.
   * Command output is written to the console PrintStream. The method will
   * loop reading commands from the console InputStream until end-of-file
   * is reached. This method will then return.
   *
   * @param args Initial set of commands to execute.
   * @throws IOException
   */
  public void console(String args[]) throws IOException {
    // first handle any args passed in from launch
    if (args != null) {
      for (int i = 0; i < args.length; i++) {
        docommand(args[i]);
      }
    }
  }

  /**
   * Command Line Interface for OSGi. The method processes the initial commands
   * and then reads and processes commands from the console InputStream.
   * Command output is written to the console PrintStream. The method will
   * loop reading commands from the console InputStream until end-of-file
   * is reached. This method will then return.
   * @throws IOException
   */
  protected void console() throws IOException {
    // wait to receive commands from console and handle them
    BufferedReader br = in;
    //cache the console prompt String
    String consolePrompt = "\r\n" + ConsoleMsg.CONSOLE_PROMPT; //$NON-NLS-1$
    while (!disconnected()) {
      out.print(consolePrompt);
      out.flush();

      String cmdline = null;
      if (blockOnready && !useSocketStream) {
        // bug 40066: avoid waiting on input stream - apparently generates contention with other native calls
        try {
          while (!br.ready())
            Thread.sleep(300);
          cmdline = br.readLine();
        } catch (InterruptedException e) {
          // do nothing; probably got disconnected
        }
      } else
        cmdline = br.readLine();

      if (cmdline == null)
        break;
      if (!shutdown)
        docommand(cmdline);
    }
  }

  /**
   *  Process the args on the command line.
   *  This method invokes a CommandInterpreter to do the actual work.
   *
   *  @param cmdline a string containing the command line arguments
   */
  protected void docommand(String cmdline) {
    if (cmdline != null && cmdline.length() > 0) {
      CommandInterpreter intcp = new FrameworkCommandInterpreter(cmdline, getServices(), this);
      String command = intcp.nextArgument();
      if (command != null) {
        intcp.execute(command);
      }
    }
  }

  /**
   * Disconnects from console if useSocketStream is set to true.  This
   * will cause the console to close from a telnet session.
   */
  public synchronized void disconnect() {
    if (!disconnect) {
      disconnect = true;
      // We don't want to close System.in and System.out
      if (useSocketStream) {
        if (s != null)
          try {
            s.close();
          } catch (IOException ioe) {
            // do nothing
          }
        if (out != null)
          out.close();
        if (in != null)
          try {
            in.close();
          } catch (IOException ioe) {
            // do nothing
          }
      }
    }
  }

  /**
   * @return are we still connected?
   */
  private synchronized boolean disconnected() {
    return disconnect;
  }

  /**
   * Reads a string from standard input until user hits the Enter key.
   *
   * @return  The string read from the standard input without the newline character.
   */
  public String getInput() {
    String input;
    try {
      /** The buffered input reader on standard in. */
      input = in.readLine();
      System.out.println("<" + input + ">"); //$NON-NLS-1$//$NON-NLS-2$
    } catch (IOException e) {
      input = ""; //$NON-NLS-1$
    }
    return input;
  }

  /**
   * Return an array of service objects for all services
   * being tracked by this <tt>ServiceTracker</tt> object.
   *
   * The array is sorted primarily by descending Service Ranking and
   * secondarily by ascending Service ID.
   *
   * @return Array of service objects or <tt>null</tt> if no service
   * are being tracked.
   */
  public Object[] getServices() {
    ServiceReference[] serviceRefs = cptracker.getServiceReferences();
    Util.dsort(serviceRefs, 0, serviceRefs.length);

    Object[] serviceObjects = new Object[serviceRefs.length];
    for (int i = 0; i < serviceRefs.length; i++)
      serviceObjects[i] = FrameworkConsole.this.context.getService(serviceRefs[i]);
    return serviceObjects;
  }

  /**
   * Stops the console so the thread can be GC'ed
   * @throws IOException
   *
   */
  public synchronized void shutdown() {
    shutdown = true;
    cptracker.close();
    disconnect();
    if (scsg != null)
      try {
        scsg.shutdown();
      } catch (IOException e) {
        System.err.println(e.getMessage());
      }
  }

  /**
   * ConsoleSocketGetter - provides a Thread that listens on the port
   * for FrameworkConsole.  If acceptConnections is set to true then
   * the thread will notify the getSocket method to return the socket.
   * If acceptConnections is set to false then the client is notified
   * that connections are not currently accepted and closes the socket.
   */
  class ConsoleSocketGetter implements Runnable {

    /** The ServerSocket to accept connections from */
    private final ServerSocket server;
    /** The current socket to be returned by getSocket */
    private Socket socket;
    /** if set to true then allow the socket to be returned by getSocket */
    private boolean acceptConnections = true;
    /** Lock object to synchronize returning of the socket */
    private final Object lock = new Object();

    /**
     * Constructor - sets the server and starts the thread to
     * listen for connections.
     *
     * @param server a ServerSocket to accept connections from
     */
    ConsoleSocketGetter(ServerSocket server) {
      this.server = server;
      Thread t = new Thread(this, "ConsoleSocketGetter"); //$NON-NLS-1$
      t.setDaemon(true);
      t.start();
    }

    public void run() {
      while (!shutdown) {
        try {
          socket = server.accept();
          if (!acceptConnections) {
            PrintWriter o = createPrintWriter(socket.getOutputStream());
            o.println(ConsoleMsg.CONSOLE_TELNET_CONNECTION_REFUSED);
            o.println(ConsoleMsg.CONSOLE_TELNET_CURRENTLY_USED);
            o.println(ConsoleMsg.CONSOLE_TELNET_ONE_CLIENT_ONLY);
            o.close();
            socket.close();
          } else {
            synchronized (lock) {
              lock.notify();
            }
          }
        } catch (Exception e) {
          if (!shutdown)
            e.printStackTrace();
        }

      }
    }

    /**
     * Method to get a socket connection from a client.
     *
     * @return - Socket from a connected client
     */
    public Socket getSocket() throws InterruptedException {
      // wait for a socket to get assigned from the accepter thread
      synchronized (lock) {
        lock.wait(); //TODO spurious wakeup not handled
      }
      setAcceptConnections(false);
      return socket;
    }

    /**
     * Method to indicate if connections are accepted or not.  If set
     * to false then the clients will be notified that connections
     * are not accepted.
     */
    public void setAcceptConnections(boolean acceptConnections) {
      this.acceptConnections = acceptConnections;
    }

    public void shutdown() throws IOException {
      server.close();
    }
  }

}
TOP

Related Classes of org.eclipse.osgi.framework.internal.core.FrameworkConsole$ConsoleSocketGetter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.