/** * Copyright 2008 - CommonCrawl Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * **/ package org.commoncrawl.service.directory; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.charset.Charset; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.record.Buffer; import org.commoncrawl.async.EventLoop; import org.commoncrawl.async.Timer; import org.commoncrawl.crawl.common.internal.CrawlEnvironment; import org.commoncrawl.rpc.base.internal.AsyncClientChannel; import org.commoncrawl.rpc.base.internal.AsyncContext; import org.commoncrawl.rpc.base.internal.AsyncRequest; import org.commoncrawl.rpc.base.internal.AsyncServerChannel; import org.commoncrawl.rpc.base.internal.NullMessage; import org.commoncrawl.rpc.base.internal.Server; import org.commoncrawl.rpc.base.shared.RPCException; import org.commoncrawl.util.CCStringUtils; public class DirectoryServiceTester extends Server implements DirectoryServiceCallback, AsyncServerChannel.ConnectionCallback, AsyncClientChannel.ConnectionCallback { private static final Log LOG = LogFactory.getLog(DirectoryServiceTester.class); EventLoop _eventLoop = null; InetSocketAddress _address = null; AsyncClientChannel _channel; DirectoryService.AsyncStub _serviceStub; long _connectionCookie = 0; public static void main(String[] args) { InetSocketAddress socketAddress = new InetSocketAddress(args[0],Integer.parseInt(args[1])); if (socketAddress != null) { DirectoryServiceTester tester = new DirectoryServiceTester(socketAddress); LOG.info("Waiting for Event Loop to Terminate"); try { tester._eventLoop.getEventThread().join(); } catch (InterruptedException e) { } LOG.info("Event Loop Terminated"); } else { LOG.error("Invalid Local Address Specified!"); } } public DirectoryServiceTester(InetSocketAddress address) { _eventLoop = new EventLoop(); _address = address; _eventLoop.start(); // create server channel ... AsyncServerChannel channel = new AsyncServerChannel(this, _eventLoop,_address,this); // register RPC services it supports ... registerService(channel,DirectoryServiceCallback.spec); try { start(); } catch (IOException e) { LOG.error(CCStringUtils.stringifyException(e)); _eventLoop.stop(); return; } _eventLoop.setTimer(new Timer(0,false,new Timer.Callback() { @Override public void timerFired(Timer timer) { connect(); } })); } void connect() { try { _channel = new AsyncClientChannel(_eventLoop,_address,new InetSocketAddress(_address.getAddress(),CrawlEnvironment.DIRECTORY_SERVICE_RPC_PORT),this); _channel.open(); _serviceStub = new DirectoryService.AsyncStub(_channel); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } void queryItem(final String path)throws IOException { DirectoryServiceQuery queryRequest = new DirectoryServiceQuery(); queryRequest.setItemPath(path); _serviceStub.query(queryRequest, new AsyncRequest.Callback<DirectoryServiceQuery, DirectoryServiceItemList>(){ @Override public void requestComplete(AsyncRequest<DirectoryServiceQuery, DirectoryServiceItemList> request) { dumpItemList(request.getOutput()); } }); } void publishTestItem(final String path,String testBuffer)throws IOException { byte bytes[] = testBuffer.getBytes(Charset.forName("UTF8")); DirectoryServiceItem item = new DirectoryServiceItem(); item.setItemPath(path); item.setItemData(new Buffer(bytes)); _serviceStub.publish(item,new AsyncRequest.Callback<DirectoryServiceItem, DirectoryServiceItem>() { @Override public void requestComplete(AsyncRequest<DirectoryServiceItem, DirectoryServiceItem> request) { LOG.info("Publish of Item:" + path + " Completed."); } }); } void startTest() { LOG.info("Starting Tests"); DirectoryServiceSubscriptionInfo subscription = new DirectoryServiceSubscriptionInfo(); subscription.setSubscriptionPath("/test/zzz/.*"); try { LOG.info("Subscribing to .*"); _serviceStub.subscribe(subscription,new AsyncRequest.Callback<DirectoryServiceSubscriptionInfo,DirectoryServiceItemList>() { @Override public void requestComplete(AsyncRequest<DirectoryServiceSubscriptionInfo, DirectoryServiceItemList> request) { dumpItemList(request.getOutput()); try { long currentTime = System.currentTimeMillis(); LOG.info("Subscription Successfull. Publishing Items... Seed:" + currentTime); publishTestItem("/test/foo/bar","bar"+ currentTime); publishTestItem("/test/foo/bar2","bar2" + currentTime); publishTestItem("/test/foo/bar3","bar3" + currentTime); publishTestItem("/test/zzz/bar","zbar" + currentTime); publishTestItem("/test/zzz/bar2","zbar2" + currentTime); publishTestItem("/test/zzz/bar3","zbar3" + currentTime); LOG.info("Publish Successfull. querying Items..."); // queryItem("/test/foo/bar"); // queryItem("/test/foo/bar2"); // queryItem("/test/foo/bar3"); // queryItem("/test/zzz/bar"); // queryItem("/test/zzz/bar2"); // queryItem("/test/zzz/bar3"); LOG.info("Done..."); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); } catch (IOException e) { LOG.error(CCStringUtils.stringifyException(e)); } } void dumpItemList(DirectoryServiceItemList itemList) { for (DirectoryServiceItem item: itemList.getItems()) { String value = Charset.forName("UTF-8").decode(ByteBuffer.wrap(item.getItemData().getReadOnlyBytes())).toString(); System.out.println("item:" + item.getItemPath() + " changed to version:" + item.getVersionNumber() + "Value:" + value); } } @Override public void itemChanged(AsyncContext<DirectoryServiceItemList, NullMessage> rpcContext) throws RPCException { dumpItemList(rpcContext.getInput()); rpcContext.completeRequest(); } @Override public void IncomingClientConnected(AsyncClientChannel channel) { } @Override public void IncomingClientDisconnected(AsyncClientChannel channel) { } @Override public void OutgoingChannelConnected(AsyncClientChannel channel) { LOG.info("Connected to Directory Server. Initiating Registration"); DirectoryServiceRegistrationInfo registrationInfo = new DirectoryServiceRegistrationInfo(); _connectionCookie = System.currentTimeMillis(); registrationInfo.setConnectionString(_address.getAddress().getHostAddress() + ":" + _address.getPort()); registrationInfo.setRegistrationCookie(_connectionCookie); try { _serviceStub.register(registrationInfo,new AsyncRequest.Callback<DirectoryServiceRegistrationInfo,NullMessage>() { @Override public void requestComplete(AsyncRequest<DirectoryServiceRegistrationInfo, NullMessage> request) { } }); } catch (IOException e) { LOG.error(CCStringUtils.stringifyException(e)); _eventLoop.stop(); } } @Override public boolean OutgoingChannelDisconnected(AsyncClientChannel channel) { // TODO Auto-generated method stub return false; } @Override public void initialize(AsyncContext<DirectoryServiceRegistrationInfo, NullMessage> rpcContext)throws RPCException { LOG.info("Received Initialization Request on Callback Channel"); if (rpcContext.getInput().getRegistrationCookie() == _connectionCookie) { LOG.info("Callback Cookie is Valid. Starting Test"); rpcContext.setStatus(AsyncRequest.Status.Success); rpcContext.completeRequest(); startTest(); } else { LOG.error("Connection Cookies Don't Match!"); _eventLoop.stop(); } } }