diff --git a/pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerAdminApiApplication.java b/pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerAdminApiApplication.java
index b0fd1d283506..75f01ce5e4eb 100644
--- a/pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerAdminApiApplication.java
+++ b/pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerAdminApiApplication.java
@@ -26,6 +26,7 @@
import org.apache.pinot.broker.requesthandler.BrokerRequestHandler;
import org.apache.pinot.broker.routing.RoutingManager;
import org.apache.pinot.common.metrics.BrokerMetrics;
+import org.apache.pinot.core.api.ServiceAutoDiscoveryFeature;
import org.apache.pinot.core.transport.ListenerConfig;
import org.apache.pinot.core.util.ListenerConfigUtil;
import org.apache.pinot.spi.env.PinotConfiguration;
@@ -51,7 +52,7 @@ public BrokerAdminApiApplication(RoutingManager routingManager, BrokerRequestHan
packages(RESOURCE_PACKAGE);
property(PINOT_CONFIGURATION, brokerConf);
if (brokerConf.getProperty(CommonConstants.Broker.BROKER_SERVICE_AUTO_DISCOVERY, false)) {
- register(BrokerServiceAutoDiscoveryFeature.class);
+ register(ServiceAutoDiscoveryFeature.class);
}
register(new AbstractBinder() {
@Override
diff --git a/pinot-controller/src/main/java/org/apache/pinot/controller/api/ControllerAdminApiApplication.java b/pinot-controller/src/main/java/org/apache/pinot/controller/api/ControllerAdminApiApplication.java
index 8b2e69e49d4b..3f060dead931 100644
--- a/pinot-controller/src/main/java/org/apache/pinot/controller/api/ControllerAdminApiApplication.java
+++ b/pinot-controller/src/main/java/org/apache/pinot/controller/api/ControllerAdminApiApplication.java
@@ -28,6 +28,7 @@
import javax.ws.rs.container.ContainerResponseFilter;
import org.apache.pinot.controller.ControllerConf;
import org.apache.pinot.controller.api.access.AuthenticationFilter;
+import org.apache.pinot.core.api.ServiceAutoDiscoveryFeature;
import org.apache.pinot.core.transport.ListenerConfig;
import org.apache.pinot.core.util.ListenerConfigUtil;
import org.apache.pinot.spi.utils.CommonConstants;
@@ -57,6 +58,9 @@ public ControllerAdminApiApplication(ControllerConf conf) {
packages(_controllerResourcePackages);
// TODO See ControllerResponseFilter
// register(new LoggingFeature());
+ if (conf.getProperty(CommonConstants.Controller.CONTROLLER_SERVICE_AUTO_DISCOVERY, false)) {
+ register(ServiceAutoDiscoveryFeature.class);
+ }
register(JacksonFeature.class);
register(MultiPartFeature.class);
registerClasses(io.swagger.jaxrs.listing.ApiListingResource.class);
diff --git a/pinot-core/pom.xml b/pinot-core/pom.xml
index 244fa30dcfc2..90bb06eab24e 100644
--- a/pinot-core/pom.xml
+++ b/pinot-core/pom.xml
@@ -179,6 +179,10 @@
org.glassfish.grizzly
grizzly-http-server
+
+ org.glassfish.hk2
+ hk2-locator
+
diff --git a/pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerServiceAutoDiscoveryFeature.java b/pinot-core/src/main/java/org/apache/pinot/core/api/ServiceAutoDiscoveryFeature.java
similarity index 95%
rename from pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerServiceAutoDiscoveryFeature.java
rename to pinot-core/src/main/java/org/apache/pinot/core/api/ServiceAutoDiscoveryFeature.java
index f1a2d2d05eef..458aa4d69bbc 100644
--- a/pinot-broker/src/main/java/org/apache/pinot/broker/broker/BrokerServiceAutoDiscoveryFeature.java
+++ b/pinot-core/src/main/java/org/apache/pinot/core/api/ServiceAutoDiscoveryFeature.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.pinot.broker.broker;
+package org.apache.pinot.core.api;
import java.io.IOException;
import javax.inject.Inject;
@@ -31,6 +31,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
/**
* Auto scan and discovery classes annotated with Service tags. This enables the feature similar to Spring's
* auto-discovery, that if a class is annotated with some tags like @Service, the class will be auto-loaded
@@ -68,8 +69,8 @@
* pinot-integration-tests/src/main/java/org/apache/pinot/broker/integration/tests/BrokerTestAutoLoadedService.java
*
*/
-public class BrokerServiceAutoDiscoveryFeature implements Feature {
- private static final Logger LOGGER = LoggerFactory.getLogger(BrokerServiceAutoDiscoveryFeature.class);
+public class ServiceAutoDiscoveryFeature implements Feature {
+ private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAutoDiscoveryFeature.class);
@Inject
ServiceLocator _serviceLocator;
diff --git a/pinot-integration-tests/src/main/java/org/apache/pinot/broker/api/resources/EchoWithAutoDiscovery.java b/pinot-integration-tests/src/main/java/org/apache/pinot/broker/api/resources/BrokerEchoWithAutoDiscovery.java
similarity index 89%
rename from pinot-integration-tests/src/main/java/org/apache/pinot/broker/api/resources/EchoWithAutoDiscovery.java
rename to pinot-integration-tests/src/main/java/org/apache/pinot/broker/api/resources/BrokerEchoWithAutoDiscovery.java
index 6d6787233342..445048f46908 100644
--- a/pinot-integration-tests/src/main/java/org/apache/pinot/broker/api/resources/EchoWithAutoDiscovery.java
+++ b/pinot-integration-tests/src/main/java/org/apache/pinot/broker/api/resources/BrokerEchoWithAutoDiscovery.java
@@ -26,7 +26,7 @@
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
-import org.apache.pinot.broker.integration.tests.BrokerTestAutoLoadedService;
+import org.apache.pinot.core.api.AutoLoadedServiceForTest;
/**
* This class is a typical "echo" service that will return whatever string you call GET with a path.
@@ -35,9 +35,9 @@
*/
@Api(tags = "Test")
@Path("/test")
-public class EchoWithAutoDiscovery {
+public class BrokerEchoWithAutoDiscovery {
@Inject
- public BrokerTestAutoLoadedService _injectedService;
+ public AutoLoadedServiceForTest _injectedService;
@GET
@Path("/echo/{table}")
@Produces(MediaType.TEXT_PLAIN)
diff --git a/pinot-integration-tests/src/main/java/org/apache/pinot/controller/api/resources/ControllerEchoWithAutoDiscovery.java b/pinot-integration-tests/src/main/java/org/apache/pinot/controller/api/resources/ControllerEchoWithAutoDiscovery.java
new file mode 100644
index 000000000000..66248c31cc10
--- /dev/null
+++ b/pinot-integration-tests/src/main/java/org/apache/pinot/controller/api/resources/ControllerEchoWithAutoDiscovery.java
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.pinot.controller.api.resources;
+
+import io.swagger.annotations.Api;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import org.apache.pinot.core.api.AutoLoadedServiceForTest;
+
+
+/**
+ * This class is a typical "echo" service that will return whatever string you call GET with a path.
+ * It is both an integration test and a demonstration of how to dynamically add an endpoint to broker,
+ * create auto-service discovery
+ */
+@Api(tags = "Test")
+@Path("/test")
+public class ControllerEchoWithAutoDiscovery {
+ @Inject
+ public AutoLoadedServiceForTest _injectedService;
+ @GET
+ @Path("/echo/{table}")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String echo(@PathParam("table") String table) {
+ return _injectedService.echo(table);
+ }
+}
diff --git a/pinot-integration-tests/src/main/java/org/apache/pinot/broker/integration/tests/BrokerTestAutoLoadedService.java b/pinot-integration-tests/src/main/java/org/apache/pinot/core/api/AutoLoadedServiceForTest.java
similarity index 91%
rename from pinot-integration-tests/src/main/java/org/apache/pinot/broker/integration/tests/BrokerTestAutoLoadedService.java
rename to pinot-integration-tests/src/main/java/org/apache/pinot/core/api/AutoLoadedServiceForTest.java
index fa0434ba54d5..f88617672e24 100644
--- a/pinot-integration-tests/src/main/java/org/apache/pinot/broker/integration/tests/BrokerTestAutoLoadedService.java
+++ b/pinot-integration-tests/src/main/java/org/apache/pinot/core/api/AutoLoadedServiceForTest.java
@@ -16,14 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.pinot.broker.integration.tests;
+package org.apache.pinot.core.api;
import javax.inject.Singleton;
import org.jvnet.hk2.annotations.Service;
@Service
@Singleton
-public class BrokerTestAutoLoadedService {
+public class AutoLoadedServiceForTest {
public String echo(String echoText) {
return echoText;
}
diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BrokerServiceDiscoveryIntegrationTest.java b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BrokerServiceDiscoveryIntegrationTest.java
index da93bad28f75..207d2f64eeae 100644
--- a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BrokerServiceDiscoveryIntegrationTest.java
+++ b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/BrokerServiceDiscoveryIntegrationTest.java
@@ -28,7 +28,7 @@
import org.testng.annotations.Test;
/**
- * Integration test that converts Avro data for 12 segments and runs queries against it.
+ * Integration test that starts one broker with auto-discovered echo service and test it
*/
public class BrokerServiceDiscoveryIntegrationTest extends BaseClusterIntegrationTestSet {
private static final String TENANT_NAME = "TestTenant";
diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ControllerServiceDiscoveryIntegrationTest.java b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ControllerServiceDiscoveryIntegrationTest.java
new file mode 100644
index 000000000000..72fc96129e4d
--- /dev/null
+++ b/pinot-integration-tests/src/test/java/org/apache/pinot/integration/tests/ControllerServiceDiscoveryIntegrationTest.java
@@ -0,0 +1,92 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.pinot.integration.tests;
+
+import java.util.Map;
+import org.apache.commons.io.FileUtils;
+import org.apache.pinot.spi.env.PinotConfiguration;
+import org.apache.pinot.spi.utils.CommonConstants;
+import org.apache.pinot.util.TestUtils;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+
+/**
+ * Integration test that starts one broker with auto-discovered echo service and test it
+ */
+public class ControllerServiceDiscoveryIntegrationTest extends BaseClusterIntegrationTestSet {
+ private static final String TENANT_NAME = "TestTenant";
+
+ @Override
+ protected String getBrokerTenant() {
+ return TENANT_NAME;
+ }
+
+ @Override
+ protected String getServerTenant() {
+ return TENANT_NAME;
+ }
+
+ @Override
+ public Map getDefaultControllerConfiguration() {
+ Map retVal = super.getDefaultControllerConfiguration();
+ retVal.put(CommonConstants.Controller.CONTROLLER_SERVICE_AUTO_DISCOVERY, true);
+ return retVal;
+ }
+
+ @Override
+ protected PinotConfiguration getDefaultBrokerConfiguration() {
+ PinotConfiguration config = new PinotConfiguration();
+ config.setProperty(CommonConstants.Broker.BROKER_SERVICE_AUTO_DISCOVERY, true);
+ return config;
+ }
+
+ @BeforeClass
+ public void setUp()
+ throws Exception {
+ TestUtils.ensureDirectoriesExistAndEmpty(_tempDir, _segmentDir, _tarDir);
+
+ // Start the Pinot cluster
+ startZk();
+ startController();
+ startBrokers(1);
+ startServers(1);
+ }
+ @AfterClass
+ public void tearDown()
+ throws Exception {
+
+ // Brokers and servers has been stopped
+ stopBroker();
+ stopController();
+ stopZk();
+ FileUtils.deleteDirectory(_tempDir);
+ }
+
+ @Test
+ public void testControllerExtraEndpointsAutoLoaded()
+ throws Exception {
+ String response = sendGetRequest(_controllerBaseApiUrl + "/test/echo/doge");
+ Assert.assertEquals(response, "doge");
+ response = sendGetRequest(_brokerBaseApiUrl + "/test/echo/doge");
+ Assert.assertEquals(response, "doge");
+ }
+}
diff --git a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java
index bf2922b73e2b..4a8c77424e27 100644
--- a/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java
+++ b/pinot-spi/src/main/java/org/apache/pinot/spi/utils/CommonConstants.java
@@ -442,6 +442,8 @@ public static class Controller {
public static final String CONFIG_OF_INSTANCE_ID = "pinot.controller.instance.id";
public static final String CONFIG_OF_CONTROLLER_QUERY_REWRITER_CLASS_NAMES =
"pinot.controller.query.rewriter.class.names";
+ //Set to true to load all services tagged and compiled with hk2-metadata-generator. Default to False
+ public static final String CONTROLLER_SERVICE_AUTO_DISCOVERY = "pinot.controller.service.auto.discovery";
}
public static class Minion {