/*
 * Copyright 2000-2013 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.ide;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import gnu.trove.THashMap;
import org.apache.xmlrpc.*;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBufferInputStream;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.QueryStringDecoder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.ide.HttpRequestHandler;
import org.jetbrains.io.Responses;

import java.io.IOException;
import java.util.Arrays;

public class XmlRpcServerImpl implements XmlRpcServer {
  private static final Logger LOG = Logger.getInstance(XmlRpcServerImpl.class);

  private final XmlRpcHandlerMappingImpl handlerMapping;
  // idea doesn't use authentication
  private final XmlRpcContext xmlRpcContext = new XmlRpcContext() {
    @Nullable
    @Override
    public String getUserName() {
      return null;
    }

    @Nullable
    @Override
    public String getPassword() {
      return null;
    }

    @Override
    public XmlRpcHandlerMapping getHandlerMapping() {
      return handlerMapping;
    }
  };

  public XmlRpcServerImpl() {
    handlerMapping = LOG.isDebugEnabled() ? new LoggingDefaultHandlerMapping() : new XmlRpcHandlerMappingImpl();

    for (XmlRpcHandlerBean handlerBean : Extensions.getExtensions(XmlRpcHandlerBean.EP_NAME)) {
      final Object handler;
      try {
        handler = handlerBean.instantiate();
      }
      catch (ClassNotFoundException e) {
        LOG.error(e);
        continue;
      }
      handlerMapping.addHandler(handlerBean.name, handler);
    }

    LOG.debug("XmlRpcServerImpl instantiated, handlers " + handlerMapping);
  }

  static final class XmlRpcRequestHandler extends HttpRequestHandler {
    @Override
    public boolean isSupported(HttpRequest request) {
      return request == HttpMethod.POST || request == HttpMethod.OPTIONS;
    }

    @Override
    public boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context) throws IOException {
      return ((XmlRpcServerImpl)SERVICE.getInstance()).process(urlDecoder, request, context);
    }
  }

  @Override
  public boolean hasHandler(String name) {
    return handlerMapping.handlers.containsKey(name);
  }

  public void addHandler(String name, Object handler) {
    handlerMapping.addHandler(name, handler);
  }

  public void removeHandler(String name) {
    handlerMapping.removeHandler(name);
  }

  private boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context) throws IOException {
    if (!(urlDecoder.getPath().isEmpty() || urlDecoder.getPath().equals("/") || urlDecoder.getPath().equalsIgnoreCase("/RPC2"))) {
      return false;
    }

    if (request.getMethod() == HttpMethod.POST) {
      ChannelBuffer result;
      ChannelBufferInputStream in = new ChannelBufferInputStream(request.getContent());
      try {
        result = ChannelBuffers.copiedBuffer(new XmlRpcWorker(handlerMapping).execute(in, xmlRpcContext));
      }
      catch (Throwable ex) {
        context.getChannel().close();
        LOG.error(ex);
        return true;
      }
      finally {
        in.close();
      }

      HttpResponse response = Responses.create("text/xml");
      response.setContent(result);
      Responses.send(response, request, context);
      return true;
    }
    else if (HttpMethod.POST.getName().equals(request.getHeader("Access-Control-Request-Method"))) {
      assert request.getMethod() == HttpMethod.OPTIONS;
      HttpResponse response = Responses.create("text/plain");
      response.setHeader("Access-Control-Allow-Origin", "*");
      response.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
      Responses.send(response, request, context);
      return true;
    }
    return false;
  }

  private static class XmlRpcHandlerMappingImpl implements XmlRpcHandlerMapping {
    protected final THashMap<String, Object> handlers = new THashMap<String, Object>();

    public void addHandler(@NotNull String handlerName, @NotNull Object handler) {
      if (handler instanceof XmlRpcHandler) {
        handlers.put(handlerName, handler);
      }
      else {
        handlers.put(handlerName, new Invoker(handler));
      }
    }

    public void removeHandler(String handlerName) {
      handlers.remove(handlerName);
    }

    public Object getHandler(String methodName) {
      Object handler = null;
      String handlerName = null;
      int dot = methodName.lastIndexOf('.');
      if (dot > -1) {
        handlerName = methodName.substring(0, dot);
        handler = handlers.get(handlerName);
      }

      if (handler != null) {
        return handler;
      }

      IllegalStateException exception;
      if (dot > -1) {
        exception = new IllegalStateException("RPC handler object \"" + handlerName + "\" not found");
      }
      else {
        exception = new IllegalStateException("RPC handler object not found for \"" + methodName);
      }

      LOG.error(exception);
      throw exception;
    }
  }

  private static class LoggingDefaultHandlerMapping extends XmlRpcHandlerMappingImpl {
    @Override
    public void addHandler(@NotNull String handlerName, @NotNull Object handler) {
      LOG.debug(String.format("addHandler: handlerName: %s, handler: %s%s", handlerName, handler, getHandlers()));
      super.addHandler(handlerName, handler);
    }

    @Override
    public void removeHandler(String handlerName) {
      LOG.debug(String.format("removeHandler: handlerName: %s%s", handlerName, getHandlers()));
      super.removeHandler(handlerName);
    }

    @Override
    public Object getHandler(String methodName) {
      LOG.debug(String.format("getHandler: methodName: %s%s", methodName, getHandlers()));
      return super.getHandler(methodName);
    }

    private String getHandlers() {
      return String.format("%nhandlers: %s %s", Arrays.toString(handlers.keySet().toArray()), Arrays.toString(handlers.values().toArray()));
    }

    @Override
    public String toString() {
      return getHandlers();
    }
  }
}
@@ -2727,32 +2727,44 @@
   return request
+.getMethod()
  == HttpMethod.P
@@ -2777,16 +2777,28 @@
  request
+.getMethod()
  == Http
@@ -3518,16 +3518,31 @@
    if (!
+isXmlRpcRequest
 (urlDeco
@@ -3557,104 +3557,8 @@
 ath(
-).isEmpty() %7C%7C urlDecoder.getPath().equals(%22/%22) %7C%7C urlDecoder.getPath().equalsIgnoreCase(%22/RPC2%22
 ))) 
@@ -4663,24 +4663,195 @@
 false;%0A  %7D%0A%0A
+  private static boolean isXmlRpcRequest(String path) %7B%0A    return path.isEmpty() %7C%7C (path.length() == 1 && path.charAt(0) == '/') %7C%7C path.equalsIgnoreCase(%22/RPC2%22);%0A  %7D%0A%0A
   private st

fix isSupported after last commit