mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
http request handlers should not be netty (third-party dependency) channel handlers
xml rpc server serve now only "/" and "/RPC2" (case-insensitive) urls
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -17,9 +17,6 @@ package com.intellij.ide;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
*/
|
||||
public interface XmlRpcServer {
|
||||
void addHandler(String name, Object handler);
|
||||
boolean hasHandler(String name);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 org.jetbrains.ide;
|
||||
|
||||
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.QueryStringDecoder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class HttpRequestHandler {
|
||||
public boolean isSupported(HttpMethod method) {
|
||||
return method == HttpMethod.GET;
|
||||
}
|
||||
|
||||
public abstract boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context)
|
||||
throws IOException;
|
||||
}
|
||||
@@ -1,15 +1,27 @@
|
||||
/*
|
||||
* 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 org.jetbrains.ide;
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jboss.netty.channel.ChannelFutureListener;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
|
||||
public abstract class WebServerManager {
|
||||
// Your handler will be instantiated on first user request
|
||||
public static final ExtensionPointName<Consumer<ChannelPipeline>> EP_NAME =
|
||||
ExtensionPointName.create("com.intellij.serverPipelineConsumer");
|
||||
public static final ExtensionPointName<HttpRequestHandler> EP_NAME = ExtensionPointName.create("com.intellij.httpRequestHandler");
|
||||
|
||||
public static WebServerManager getInstance() {
|
||||
return ServiceManager.getService(WebServerManager.class);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
* 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.
|
||||
@@ -17,24 +17,25 @@ package com.intellij.ide;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.util.Consumer;
|
||||
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.*;
|
||||
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;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class XmlRpcServerImpl extends SimpleChannelUpstreamHandler implements XmlRpcServer {
|
||||
public class XmlRpcServerImpl implements XmlRpcServer {
|
||||
private static final Logger LOG = Logger.getInstance(XmlRpcServerImpl.class);
|
||||
|
||||
private final XmlRpcHandlerMappingImpl handlerMapping;
|
||||
@@ -76,11 +77,15 @@ public class XmlRpcServerImpl extends SimpleChannelUpstreamHandler implements Xm
|
||||
LOG.debug("XmlRpcServerImpl instantiated, handlers " + handlerMapping);
|
||||
}
|
||||
|
||||
static final class XmlRpcPipelineConsumer implements Consumer<ChannelPipeline> {
|
||||
static final class XmlRpcRequestHandler extends HttpRequestHandler {
|
||||
@Override
|
||||
public void consume(ChannelPipeline pipeline) {
|
||||
XmlRpcServer xmlRpcServer = SERVICE.getInstance();
|
||||
pipeline.addLast("pluggable_xmlRpc", (XmlRpcServerImpl)xmlRpcServer);
|
||||
public boolean isSupported(HttpMethod method) {
|
||||
return method == HttpMethod.POST || method == HttpMethod.OPTIONS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context) throws IOException {
|
||||
return ((XmlRpcServerImpl)SERVICE.getInstance()).process(urlDecoder, request, context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,52 +102,40 @@ public class XmlRpcServerImpl extends SimpleChannelUpstreamHandler implements Xm
|
||||
handlerMapping.removeHandler(name);
|
||||
}
|
||||
|
||||
public void messageReceived(ChannelHandlerContext context, MessageEvent e) throws Exception {
|
||||
if (e.getMessage() instanceof HttpRequest) {
|
||||
HttpRequest request = (HttpRequest)e.getMessage();
|
||||
private boolean process(QueryStringDecoder urlDecoder, HttpRequest request, ChannelHandlerContext context) throws IOException {
|
||||
if (!(urlDecoder.getPath().isEmpty() || 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;
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
HttpResponse response = Responses.create("text/xml");
|
||||
response.setContent(result);
|
||||
Responses.send(response, request, context);
|
||||
return;
|
||||
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();
|
||||
}
|
||||
|
||||
if (request.getMethod() == HttpMethod.OPTIONS &&
|
||||
HttpMethod.POST.getName().equals(request.getHeader("Access-Control-Request-Method"))) {
|
||||
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;
|
||||
}
|
||||
HttpResponse response = Responses.create("text/xml");
|
||||
response.setContent(result);
|
||||
Responses.send(response, request, context);
|
||||
return true;
|
||||
}
|
||||
|
||||
context.sendUpstream(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext context, ExceptionEvent e) throws Exception {
|
||||
try {
|
||||
LOG.error(e.getCause());
|
||||
}
|
||||
finally {
|
||||
e.getChannel().close();
|
||||
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 {
|
||||
|
||||
@@ -9,16 +9,11 @@ import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.startup.StartupActivity;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.SimpleTimer;
|
||||
import com.intellij.util.Consumer;
|
||||
import org.jboss.netty.channel.ChannelException;
|
||||
import org.jboss.netty.channel.ChannelFutureListener;
|
||||
import org.jboss.netty.channel.ChannelPipeline;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.io.WebServer;
|
||||
@@ -114,18 +109,7 @@ class WebServerManagerImpl extends WebServerManager implements Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
detectedPortNumber = server.start(getDefaultPort(), PORTS_COUNT, true, new Computable<Consumer<ChannelPipeline>[]>() {
|
||||
@Override
|
||||
public Consumer<ChannelPipeline>[] compute() {
|
||||
Consumer<ChannelPipeline>[] consumers = Extensions.getExtensions(EP_NAME);
|
||||
if (consumers.length == 0) {
|
||||
LOG.warn("web server will be stopped, there are no pipeline consumers");
|
||||
SimpleTimer.getInstance().setUp(server.createShutdownTask(), 3000);
|
||||
}
|
||||
return consumers;
|
||||
}
|
||||
});
|
||||
|
||||
detectedPortNumber = server.start(getDefaultPort(), PORTS_COUNT, true);
|
||||
if (detectedPortNumber == -1) {
|
||||
LOG.info("web server cannot be started, cannot bind to port");
|
||||
}
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
/*
|
||||
* 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 org.jetbrains.io;
|
||||
|
||||
import com.intellij.openapi.application.Application;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ex.ApplicationInfoEx;
|
||||
import org.jboss.netty.buffer.BigEndianHeapChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffer;
|
||||
import org.jboss.netty.buffer.ChannelBuffers;
|
||||
import org.jboss.netty.channel.ChannelFuture;
|
||||
import org.jboss.netty.channel.ChannelFutureListener;
|
||||
@@ -74,7 +90,10 @@ public final class Responses {
|
||||
}
|
||||
|
||||
public static void send(HttpResponse response, HttpRequest request, ChannelHandlerContext context) {
|
||||
setContentLength(response, response.getContent().readableBytes());
|
||||
ChannelBuffer content = response.getContent();
|
||||
if (content != ChannelBuffers.EMPTY_BUFFER) {
|
||||
setContentLength(response, content.readableBytes());
|
||||
}
|
||||
send(response, context, !isKeepAlive(request));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,8 @@ package org.jetbrains.io;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.ShutDownTracker;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jboss.netty.bootstrap.ClientBootstrap;
|
||||
@@ -35,7 +33,9 @@ import org.jboss.netty.handler.codec.http.*;
|
||||
import org.jboss.netty.util.CharsetUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.ide.HttpRequestHandler;
|
||||
import org.jetbrains.ide.PooledThreadExecutor;
|
||||
import org.jetbrains.ide.WebServerManager;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -71,26 +71,18 @@ public class WebServer {
|
||||
return !openChannels.isEmpty();
|
||||
}
|
||||
|
||||
public void start(int port, Consumer<ChannelPipeline>... pipelineConsumers) {
|
||||
start(port, new Computable.PredefinedValueComputable<Consumer<ChannelPipeline>[]>(pipelineConsumers));
|
||||
public void start(int port) {
|
||||
start(port, 1, false);
|
||||
}
|
||||
|
||||
public void start(int port, int portsCount, Consumer<ChannelPipeline>... pipelineConsumers) {
|
||||
start(port, portsCount, false, new Computable.PredefinedValueComputable<Consumer<ChannelPipeline>[]>(pipelineConsumers));
|
||||
}
|
||||
|
||||
public void start(int port, Computable<Consumer<ChannelPipeline>[]> pipelineConsumers) {
|
||||
start(port, 1, false, pipelineConsumers);
|
||||
}
|
||||
|
||||
public int start(int firstPort, int portsCount, boolean tryAnyPort, Computable<Consumer<ChannelPipeline>[]> pipelineConsumers) {
|
||||
public int start(int firstPort, int portsCount, boolean tryAnyPort) {
|
||||
if (isRunning()) {
|
||||
throw new IllegalStateException("server already started");
|
||||
}
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap(channelFactory);
|
||||
bootstrap.setOption("child.tcpNoDelay", true);
|
||||
bootstrap.setPipelineFactory(new ChannelPipelineFactoryImpl(pipelineConsumers, new DefaultHandler(openChannels)));
|
||||
bootstrap.setPipelineFactory(new ChannelPipelineFactoryImpl(new DefaultHandler(openChannels)));
|
||||
return bind(firstPort, portsCount, tryAnyPort, bootstrap);
|
||||
}
|
||||
|
||||
@@ -307,28 +299,20 @@ public class WebServer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void replaceDefaultHandler(@NotNull ChannelHandlerContext context, @NotNull SimpleChannelUpstreamHandler messageChannelHandler) {
|
||||
context.getPipeline().replace(DefaultHandler.class, "replacedDefaultHandler", messageChannelHandler);
|
||||
}
|
||||
|
||||
private static class ChannelPipelineFactoryImpl implements ChannelPipelineFactory {
|
||||
private final Computable<Consumer<ChannelPipeline>[]> pipelineConsumers;
|
||||
private final DefaultHandler defaultHandler;
|
||||
|
||||
public ChannelPipelineFactoryImpl(Computable<Consumer<ChannelPipeline>[]> pipelineConsumers, DefaultHandler defaultHandler) {
|
||||
this.pipelineConsumers = pipelineConsumers;
|
||||
public ChannelPipelineFactoryImpl(DefaultHandler defaultHandler) {
|
||||
this.defaultHandler = defaultHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
ChannelPipeline pipeline = pipeline(new HttpRequestDecoder(), new HttpChunkAggregator(1048576), new HttpResponseEncoder());
|
||||
for (Consumer<ChannelPipeline> consumer : pipelineConsumers.compute()) {
|
||||
try {
|
||||
consumer.consume(pipeline);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
pipeline.addLast("defaultHandler", defaultHandler);
|
||||
return pipeline;
|
||||
return pipeline(new HttpRequestDecoder(), new HttpChunkAggregator(1048576), new HttpResponseEncoder(), defaultHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,21 +330,55 @@ public class WebServer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageReceived(ChannelHandlerContext context, MessageEvent e) throws Exception {
|
||||
if (e.getMessage() instanceof HttpRequest) {
|
||||
HttpRequest message = (HttpRequest)e.getMessage();
|
||||
if (new QueryStringDecoder(message.getUri()).getPath().equals(START_TIME_PATH)) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setContent(ChannelBuffers.copiedBuffer(getApplicationStartTime(), CharsetUtil.US_ASCII));
|
||||
Responses.addServer(response);
|
||||
Responses.addDate(response);
|
||||
context.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
else {
|
||||
Responses.sendError(message, context, NOT_FOUND);
|
||||
public void messageReceived(ChannelHandlerContext context, MessageEvent event) throws Exception {
|
||||
if (!(event.getMessage() instanceof HttpRequest)) {
|
||||
context.sendUpstream(event);
|
||||
}
|
||||
|
||||
HttpRequest request = (HttpRequest)event.getMessage();
|
||||
QueryStringDecoder urlDecoder = new QueryStringDecoder(request.getUri());
|
||||
if (urlDecoder.getPath().equals(START_TIME_PATH)) {
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
response.setHeader("Access-Control-Allow-Origin", "*");
|
||||
response.setContent(ChannelBuffers.copiedBuffer(getApplicationStartTime(), CharsetUtil.US_ASCII));
|
||||
Responses.addServer(response);
|
||||
Responses.addDate(response);
|
||||
Responses.send(response, context);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpRequestHandler connectedHandler = (HttpRequestHandler)context.getAttachment();
|
||||
if (connectedHandler == null) {
|
||||
for (HttpRequestHandler handler : WebServerManager.EP_NAME.getExtensions()) {
|
||||
try {
|
||||
if (handler.isSupported(request.getMethod()) && handler.process(urlDecoder, request, context)) {
|
||||
if (context.getAttachment() == null) {
|
||||
context.setAttachment(handler);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (connectedHandler.isSupported(request.getMethod())) {
|
||||
connectedHandler.process(urlDecoder, request, context);
|
||||
return;
|
||||
}
|
||||
Responses.sendError(request, context, NOT_FOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext context, ExceptionEvent event) throws Exception {
|
||||
try {
|
||||
LOG.error(event.getCause());
|
||||
}
|
||||
finally {
|
||||
context.setAttachment(null);
|
||||
event.getChannel().close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
<extensionPoint name="pathMacroFilter" interface="com.intellij.openapi.application.PathMacroFilter"/>
|
||||
<extensionPoint name="pathMacroExpendableProtocol" beanClass="com.intellij.application.options.PathMacroExpendableProtocolBean"/>
|
||||
|
||||
<extensionPoint name="serverPipelineConsumer" interface="com.intellij.util.Consumer"/>
|
||||
|
||||
<extensionPoint name="httpRequestHandler" interface="org.jetbrains.ide.HttpRequestHandler"/>
|
||||
|
||||
<extensionPoint name="colorPickerListenerFactory" interface="com.intellij.ui.ColorPickerListenerFactory"/>
|
||||
</extensionPoints>
|
||||
|
||||
@@ -289,7 +289,7 @@
|
||||
|
||||
<applicationService serviceInterface="org.jetbrains.ide.WebServerManager" serviceImplementation="org.jetbrains.ide.WebServerManagerImpl"/>
|
||||
<applicationService serviceInterface="com.intellij.ide.XmlRpcServer" serviceImplementation="com.intellij.ide.XmlRpcServerImpl"/>
|
||||
<serverPipelineConsumer implementation="com.intellij.ide.XmlRpcServerImpl$XmlRpcPipelineConsumer"/>
|
||||
<httpRequestHandler implementation="com.intellij.ide.XmlRpcServerImpl$XmlRpcRequestHandler"/>
|
||||
<postStartupActivity implementation="org.jetbrains.ide.WebServerManagerImpl$MyPostStartupActivity"/>
|
||||
|
||||
<editorNotificationProvider implementation="com.intellij.ide.FileChangedNotificationProvider"/>
|
||||
|
||||
Reference in New Issue
Block a user