content: /**
   * Copyright 2000-2006 DFKI GmbH.
   * All Rights Reserved.  Use is subject to license terms.
   * <p/>
   * This file is part of MARY TTS.
   * <p/>
   * MARY TTS is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, version 3 of the License.
   * <p/>
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU Lesser General Public License for more details.
   * <p/>
   * You should have received a copy of the GNU Lesser General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package marytts.server.http;
  
  import android.util.Log;
  
  import org.apache.http.HttpException;
  import org.apache.http.impl.DefaultConnectionReuseStrategy;
  import org.apache.http.impl.DefaultHttpResponseFactory;
  import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
  import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
  import org.apache.http.nio.NHttpConnection;
  import org.apache.http.nio.protocol.BufferingHttpServiceHandler;
  import org.apache.http.nio.protocol.EventListener;
  import org.apache.http.nio.reactor.IOEventDispatch;
  import org.apache.http.nio.reactor.ListeningIOReactor;
  import org.apache.http.params.BasicHttpParams;
  import org.apache.http.params.CoreConnectionPNames;
  import org.apache.http.params.CoreProtocolPNames;
  import org.apache.http.params.HttpParams;
  import org.apache.http.protocol.BasicHttpProcessor;
  import org.apache.http.protocol.ExecutionContext;
  import org.apache.http.protocol.HttpRequestHandlerRegistry;
  import org.apache.http.protocol.ResponseConnControl;
  import org.apache.http.protocol.ResponseContent;
  import org.apache.http.protocol.ResponseDate;
  import org.apache.http.protocol.ResponseServer;
  
  import java.io.IOException;
  import java.io.InterruptedIOException;
  import java.net.InetSocketAddress;
  
  import marytts.server.Mary;
  import marytts.server.MaryProperties;
  
  //import org.apache.log4j.Logger;
  
  /**
   * Listen for clients as an Http server at port
   * <code>MaryProperties.socketPort()</code>.
   * <p/>
   * There are two types of clients that can be handled:
   * <p/>
   * (1) Non-web browser clients
   * (2) Web browser clients
   * <p/>
   * Note that non-web browser clients can mimic web browser clients by setting WEB_BROWSER_CLIENT parameter to "true"
   * in the Http request string
   * <p/>
   * Clients can request the following (See below for more details):
   * <p/>
   * (1) A file such as Mary icon or an audio file
   * (2) Information like available voices, example texts, available audio formats, etc
   * (3) Synthesis of an appropriate input with appropriate additional parameters
   * <p/>
   * For all clients, the responses are always sent in an HttpResponse.
   * The entity in the response body can represent:
   * <p/>
   * (1) An html page (applies only to web browser clients)
   * (2) Some binary data (such as bytes of Mary icon for file requests, or bytes of audio data for synthesis requests)
   * (3) Some piece of text
   * <p/>
   * A valid Mary Http request string is a collection of individual key-value pairs combined in Http request style:
   * <code>address?pair1&pair2&pair3...</code> etc.
   * <p/>
   * The <code>address</code> identifies the kind of thing that the client is asking for:
   * <ul>
   * <li><code>version</code> requests the version of the MARY server;</li>
   * <li><code>datatypes</code> requests the list of available data types;</li>
   * <li><code>locales</code> requests the list of available locales / language components;</li>
   * <li><code>voices</code> requests the list of available voices;</li>
   * <li><code>audioformats</code> requests the list of supported audio file format types;</li>
   * <li><code>exampletext?voice=hmm-slt<code> requests the example text for the given voice;</li>
   * <li><code>exampletext?datatype=RAWMARYXML&locale=de</code> requests an example text for data of the given type and locale;</li>
   * <li><code>audioeffects</code> requests the list of default audio effects;</li>
   * <li><code>audioeffect-default-param?effect=Robot</code> requests the default parameters of the given audio effect;</li>
   * <li><code>audioeffect-full?effect=Robot&params=amount:100.0</code> requests a full description of the given audio effect, including effect name, parameters and help text;</li>
   * <li><code>audioeffect-help?effect=Robot</code> requests a help text describing the given audio effect;</li>
   * <li><code>audioeffect-is-hmm-effect?effect=Robot</code> requests a boolean value (plain text "yes" or "no") indicating whether or not the given effect is an effect that operates on HMM-based voices only;</li>
   * <li><code>features?locale=de</code> requests the list of available features that can be computed for the given locale;</li>
   * <li><code>features?voice=hmm-slt</code> requests the list of available features that can be computed for the given voice;</li>
   * <li><code>vocalizations?voice=dfki-poppy</code> requests the list of vocalization names that are available with the given voice;
   * <li><code>styles?voice=dfki-pavoque-styles</code> requests the list of style names that are available with the given voice;
   * <li><code>process</code> requests the synthesis of some text (see below).</li>
   * </ul>
   * <p/>
   * In Each pair has the following structure:
   * <p/>
   * <code>KEY=VALUE</code>
   * <p/>
   * where the following keys are used for passing additional information from server to client and/or vice versa:
   * <p/>
   * INPUT_TYPE (input data type)
   * <p/>
   * OUTPUT_TYPE (output data type)
   * <p/>
   * AUDIO (audio format. It may include streaming/non-streaming information as well.
   * Example values for non-streaming formats: AU_FILE, MP3_FILE, WAVE_FILE
   * Example values for streaming formats: AU_STREAM, MP3_STREAM)
   * <p/>
   * STYLE (Style descriptor)
   * <p/>
   * INPUT_TEXT (Input text to be synthesised)
   * <p/>
   * OUTPUT_TEXT (Output text - if the output type is not audio)
   * <p/>
   * SYNTHESIS_OUTPUT (A key to ask for synthesis, or to represent synthesis result.
   * Example values: SYNTHESIS_OUTPUT=? instantiates a synthesis request
   * In response, the server can set SYNTHESIS_OUTPUT to DONE, PENDING, or FAILED depending on the validity and type of te request
   * PENDING is a special case used for handling double requests due to <EMBED< or <OBJECT> tags in web browser client html pages
   * <p/>
   * <p/>
   * Additionally, web browser clients should use the following key-value pair to tell the server about their type:
   * <p/>
   * WEB_BROWSER_CLIENT=true (All other values will be interpreted as non-web browser client)
   * <p/>
   * An easy way to test the http server is as follows:
   * <p/>
   * (1) Run mary server in "http" mode by setting server=http in marybase.config
   * <p/>
   * (2) Copy and paste the following to a web browser´s address bar:
   * <p/>
   * http://localhost:59125/process?INPUT_TYPE=TEXT&OUTPUT_TYPE=AUDIO&INPUT_TEXT=Welcome+to+the+world+of+speech+synthesis!&AUDIO=AU&LOCALE=en_US&VOICE=hsmm-slt
   * <p/>
   * Provided that the server runs at localhost:59125 (or change "http://localhost:59125/" part as required),
   * the web browser supports AUDIO type (if not try other formats such as WAVE, MP3, OGG or install a plug-in to play the target format),
   * and the VOICE is installed (hmm-slt), the synthesis result should be sent to the web browser for playback or saving (depending on web browser settings).
   * <p/>
   *
   * @author Oytun T&uuml;rk, Marc Schr&ouml;der
   * @see InfoRequestProcessor, FileRequestProcessor, SynthesisRequestProcessor, BaselineRequestProcessor, RequestHttp, MaryWebHttpClientHandler
   */
  
  public class MaryHttpServer extends Thread {
      // private static Logger logger;
  
      private boolean isReady = false;
  
      public MaryHttpServer() {
          //  logger = MaryUtils.getLogger("server");
      }
  
      public boolean isReady() {
          return isReady;
      }
  
  
      @Override
      public void run() {
          Log.i(Mary.LOG, "Starting server.");
  
          int localPort = MaryProperties.needInteger("socket.port");
  
          HttpParams params = new BasicHttpParams();
          params
                  .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 0) // 0 means no timeout, any positive value means time out in miliseconds (i.e. 50000 for 50 seconds)
                  .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
                  .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
                  .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
                  .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
  
          BasicHttpProcessor httpproc = new BasicHttpProcessor();
          httpproc.addInterceptor(new ResponseDate());
          httpproc.addInterceptor(new ResponseServer());
          httpproc.addInterceptor(new ResponseContent());
          httpproc.addInterceptor(new ResponseConnControl());
  
          BufferingHttpServiceHandler handler = new BufferingHttpServiceHandler(
                  httpproc,
                  new DefaultHttpResponseFactory(),
                  new DefaultConnectionReuseStrategy(),
                  params);
  
          // Set up request handlers
          HttpRequestHandlerRegistry registry = new HttpRequestHandlerRegistry();
          registry.register("/process", new SynthesisRequestHandler());
          InfoRequestHandler infoRH = new InfoRequestHandler();
          registry.register("/version", infoRH);
          registry.register("/datatypes", infoRH);
          registry.register("/locales", infoRH);
          registry.register("/voices", infoRH);
          registry.register("/audioformats", infoRH);
          registry.register("/exampletext", infoRH);
          registry.register("/audioeffects", infoRH);
          registry.register("/audioeffect-default-param", infoRH);
          registry.register("/audioeffect-full", infoRH);
          registry.register("/audioeffect-help", infoRH);
          registry.register("/audioeffect-is-hmm-effect", infoRH);
          registry.register("/features", infoRH);
          registry.register("/features-discrete", infoRH);
          registry.register("/vocalizations", infoRH);
          registry.register("/styles", infoRH);
          registry.register("*", new FileRequestHandler());
  
  
          handler.setHandlerResolver(registry);
  
          // Provide an event logger
          handler.setEventListener(new EventLogger());
  
          IOEventDispatch ioEventDispatch = new DefaultServerIOEventDispatch(handler, params);
  
          int numParallelThreads = MaryProperties.getInteger("server.http.parallelthreads", 5);
  
          Log.i(Mary.LOG, "Waiting for client to connect on port " + localPort);
  
          try {
              ListeningIOReactor ioReactor = new DefaultListeningIOReactor(numParallelThreads, params);
              ioReactor.listen(new InetSocketAddress(localPort));
              isReady = true;
              ioReactor.execute(ioEventDispatch);
          } catch (InterruptedIOException ex) {
              Log.i(Mary.LOG, "Interrupted", ex);
          } catch (IOException e) {
              Log.i(Mary.LOG, "Problem with HTTP connection", e);
          }
          Log.d(Mary.LOG, "Shutdown");
      }
  
  
      static class EventLogger implements EventListener {
          @Override
          public void connectionOpen(final NHttpConnection conn) {
              Log.i(Mary.LOG,
                      "Connection from "
                              + conn.getContext().getAttribute(ExecutionContext.HTTP_TARGET_HOST) //conn.getInetAddress().getHostName()
              );
          }
  
          @Override
          public void connectionTimeout(final NHttpConnection conn) {
              Log.i(Mary.LOG, "Connection timed out: " + conn);
          }
  
          @Override
          public void connectionClosed(final NHttpConnection conn) {
              Log.i(Mary.LOG, "Connection closed: " + conn);
          }
  
          @Override
          public void fatalIOException(final IOException ex, final NHttpConnection conn) {
              Log.i(Mary.LOG, "I/O error: " + ex.getMessage());
          }
  
          @Override
          public void fatalProtocolException(final HttpException ex, final NHttpConnection conn) {
              Log.i(Mary.LOG, "HTTP error: " + ex.getMessage());
          }
      }
  }
  
  