/** * This software is licensed to you under the Apache License, Version 2.0 (the * "Apache License"). * * LinkedIn's contributions are made under the Apache License. If you contribute * to the Software, the contributions will be deemed to have been made under the * Apache License, unless you expressly indicate otherwise. Please do not make any * contributions that would be inconsistent with the Apache License. * * You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, this software * distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache * License for the specific language governing permissions and limitations for the * software governed under the Apache License. * * © 2012 LinkedIn Corp. All Rights Reserved. */ package com.senseidb.test; import java.io.File; import java.net.URL; import javax.management.InstanceAlreadyExistsException; import com.linkedin.norbert.network.Serializer; import com.senseidb.indexing.activity.facet.ActivityRangeFacetHandler; import com.senseidb.svc.impl.CoreSenseiServiceImpl; import org.apache.log4j.Logger; import org.eclipse.jetty.server.Server; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.linkedin.norbert.NorbertException; import com.linkedin.norbert.javacompat.cluster.ClusterClient; import com.linkedin.norbert.javacompat.network.NetworkServer; import com.senseidb.cluster.client.SenseiNetworkClient; import com.senseidb.conf.SenseiServerBuilder; import com.senseidb.jmx.JmxSenseiMBeanServer; import com.senseidb.search.node.SenseiBroker; import com.senseidb.search.node.SenseiRequestScatterRewriter; import com.senseidb.search.node.SenseiServer; import com.senseidb.search.node.SenseiZoieFactory; import com.senseidb.search.req.SenseiRequest; import com.senseidb.search.req.SenseiResult; import com.senseidb.svc.api.SenseiService; import com.senseidb.svc.impl.HttpRestSenseiServiceImpl; /** * Embeds all the logic for starting the test Sensei instance * */ public class SenseiStarter { private static final Logger logger = Logger.getLogger(SenseiStarter.class); public static File ConfDir1 = null; public static File ConfDir2 = null; public static File IndexDir = new File("sensei-index-test"); public static URL SenseiUrl = null; public static SenseiBroker broker = null; public static SenseiService httpRestSenseiService = null; public static SenseiServer node1; public static SenseiServer node2; public static Server httpServer1; public static Server httpServer2; public static Serializer<SenseiRequest, SenseiResult> serializer; public static SenseiNetworkClient networkClient; public static ClusterClient clusterClient; public static SenseiRequestScatterRewriter requestRewriter; public static NetworkServer networkServer1; public static NetworkServer networkServer2; public static SenseiZoieFactory<?> _zoieFactory; public static boolean started = false; public static URL federatedBrokerUrl; private static TestZkServer zkServer = new TestZkServer(); /** * Will start the new Sensei instance once per process */ public static synchronized void start(String confDir1, String confDir2) { try { zkServer.start(); } catch (Exception ex) { logger.error("Failed to start zookeeper", ex); return; } ActivityRangeFacetHandler.isSynchronized = true; if (started) { logger.warn("The server had been already started"); return; } try { JmxSenseiMBeanServer.registerCustomMBeanServer(); ConfDir1 = new File(SenseiStarter.class.getClassLoader().getResource(confDir1).toURI()); ConfDir2 = new File(SenseiStarter.class.getClassLoader().getResource(confDir2).toURI()); org.apache.log4j.PropertyConfigurator.configure("resources/log4j.properties"); loadFromSpringContext(); boolean removeSuccessful = rmrf(IndexDir); if (!removeSuccessful) { throw new IllegalStateException("The index dir " + IndexDir + " coulnd't be purged"); } SenseiServerBuilder senseiServerBuilder1 = null; senseiServerBuilder1 = new SenseiServerBuilder(ConfDir1, null); node1 = senseiServerBuilder1.buildServer(); httpServer1 = senseiServerBuilder1.buildHttpRestServer(); logger.info("Node 1 created."); SenseiServerBuilder senseiServerBuilder2 = null; senseiServerBuilder2 = new SenseiServerBuilder(ConfDir2, null); node2 = senseiServerBuilder2.buildServer(); httpServer2 = senseiServerBuilder2.buildHttpRestServer(); logger.info("Node 2 created."); broker = null; try { broker = new SenseiBroker(networkClient, clusterClient, true, serializer, 10000L, null); } catch (NorbertException ne) { logger.info("shutting down cluster...", ne); clusterClient.shutdown(); throw ne; } httpRestSenseiService = new HttpRestSenseiServiceImpl("http", "localhost", 8079, "/sensei"); logger.info("Cluster client started"); Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run(){ shutdownSensei(); }}); node1.start(true); httpServer1.start(); logger.info("Node 1 started"); node2.start(true); httpServer2.start(); logger.info("Node 2 started"); SenseiUrl = new URL("http://localhost:8079/sensei"); federatedBrokerUrl = new URL("http://localhost:8079/sensei/federatedBroker/"); waitTillServerStarts(); } catch (Throwable ex) { logger.error("Could not start the sensei", ex); throw new RuntimeException(ex); }finally { started = true; } } private static void waitTillServerStarts() throws Exception { SenseiRequest req = new SenseiRequest(); SenseiResult res = null; int count = 0; do { Thread.sleep(500); res = broker.browse(req); System.out.println(""+res.getNumHits()+" loaded..."); ++count; } while (count < 200 && res.getNumHits() < 15000); } private static void loadFromSpringContext() { ApplicationContext testSpringCtx = null; try { testSpringCtx = new ClassPathXmlApplicationContext("test-conf/sensei-test.spring"); } catch(Throwable e) { if (e instanceof InstanceAlreadyExistsException) logger.warn("norbert JMX InstanceAlreadyExistsException"); else logger.error("Unexpected Exception", e.getCause()); } networkClient = (SenseiNetworkClient)testSpringCtx.getBean("network-client"); serializer = (Serializer<SenseiRequest, SenseiResult>) testSpringCtx.getBean("serializer"); if(serializer == null) { logger.warn("Unspecified serializer, using java serialization"); serializer = CoreSenseiServiceImpl.JAVA_SERIALIZER; } clusterClient = (ClusterClient)testSpringCtx.getBean("cluster-client"); requestRewriter = (SenseiRequestScatterRewriter)testSpringCtx.getBean("request-rewriter"); networkServer1 = (NetworkServer)testSpringCtx.getBean("network-server-1"); networkServer2 = (NetworkServer)testSpringCtx.getBean("network-server-2"); _zoieFactory = (SenseiZoieFactory<?>)testSpringCtx.getBean("zoie-system-factory"); } public static boolean rmrf(File f) { if (f == null || !f.exists()) { return true; } if (f.isDirectory()) { for (File sub : f.listFiles()) { if (!rmrf(sub)) return false; } } return f.delete(); } public static void shutdownSensei() { try{ broker.shutdown();}catch(Throwable t){} try{ httpRestSenseiService.shutdown();}catch(Throwable t){} try{node1.shutdown();}catch(Throwable t){} try{httpServer1.stop();}catch(Throwable t){} try{node2.shutdown();}catch(Throwable t){} try{httpServer2.stop();}catch(Throwable t){} try{networkClient.shutdown();}catch(Throwable t){} try{clusterClient.shutdown();}catch(Throwable t){} rmrf(IndexDir); zkServer.stop(); started = false; } }