package org.codehaus.plexus.discovery.mdns; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.apache.log4j.Logger; import org.codehaus.plexus.PlexusTestCase; import org.codehaus.plexus.context.Context; import org.codehaus.plexus.discovery.DiscoverableResource; import org.codehaus.plexus.discovery.ResourceDiscoverer; import org.codehaus.plexus.discovery.ResourcePublisher; import org.codehaus.plexus.util.StringUtils; import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean; public class MDNSResourceDiscovererTestEx extends PlexusTestCase { private class BackThread extends Thread { private final Set resourceSet; private final Set foundResourceSet; final ResourceDiscoverer objResourceDiscoverer = resourceDiscoverer; private AtomicBoolean doneFlag; private BackThread(Set resourceSet, Set foundResourceSet, AtomicBoolean doneFlag) { this.resourceSet = resourceSet; this.foundResourceSet = foundResourceSet; this.doneFlag = doneFlag; } public void run() { while (!doneFlag.get()) { int resourceCount = 0; Iterator itResources = objResourceDiscoverer.findResources(); while (itResources.hasNext()) { String name = ((DiscoverableResource) itResources.next()) .getName(); synchronized (this) { if (!foundResourceSet.contains(name)) { assertTrue( "resourceSet should contain name (name=\"" + name + "\")", resourceSet .contains(name)); resourceSet.remove(name); if (LOGGER.isInfoEnabled()) LOGGER.info("consuming(name=\"" + name + "\")"); foundResourceSet.add(name); resourceCount++; } } } Thread.yield(); } } } /** * Logger */ private static final Logger LOGGER = Logger .getLogger(MDNSResourceDiscovererTestEx.class); /** * Resource Publisher */ private ResourcePublisher resourcePublisher; /** * Resource Discoverer */ private ResourceDiscoverer resourceDiscoverer; /** * Overrides customizeContext, adding the found interface address to the * context, in order to get them bound */ protected void customizeContext(Context context) throws Exception { InetAddress[] ifAddresses = null; Map addrMap = new TreeMap(); addrMap.put(Inet4Address.class.getName(), new ArrayList()); addrMap.put(Inet6Address.class.getName(), new ArrayList()); loop: for (Enumeration enmInterfaces = NetworkInterface .getNetworkInterfaces(); enmInterfaces.hasMoreElements();) { NetworkInterface curIf = ((NetworkInterface) enmInterfaces .nextElement()); for (Enumeration inetAddresses = curIf.getInetAddresses(); inetAddresses .hasMoreElements();) { InetAddress ifAddress = (InetAddress) inetAddresses .nextElement(); /** * Does this interface address suit? If don't, skip the loop */ if (!(ifAddress.isLinkLocalAddress() || ifAddress .isSiteLocalAddress()) || ifAddress.isLoopbackAddress()) continue; /** * Retrieves all the related ip address lists for this * InetAddress class then loop across them */ List ifAddrList = ((List) addrMap.get(ifAddress.getClass() .getName())); for (Iterator iterNetIf = ifAddrList.iterator(); iterNetIf .hasNext();) { /** * Retrieve the previous added address * * Tests if their MSBs (1 byte, Inet4Address, 2 bytes * Inet6Address) match. Skip if don't. Otherwise, assign to * interfaces and stop looping */ InetAddress prevIfAddress = (InetAddress) iterNetIf.next(); { boolean shouldSkip = (ifAddress.getAddress()[0] != prevIfAddress .getAddress()[0]); if (ifAddress instanceof Inet6Address) shouldSkip = (ifAddress.getAddress()[1] != prevIfAddress .getAddress()[1]); if (shouldSkip) continue; } ifAddresses = new InetAddress[] { prevIfAddress, ifAddress }; break loop; } /** * Add this ifAddress to the interface address list for this * address class */ ifAddrList.add(ifAddress); } } /** * Ultimate Sanity Check */ assertNotNull(ifAddresses); assertNotSame(ifAddresses[0], ifAddresses[1]); context.put("interface.a", ifAddresses[0].getHostAddress()); context.put("interface.b", ifAddresses[1].getHostAddress()); } protected void setUp() throws Exception { super.setUp(); this.resourcePublisher = (ResourcePublisher) lookup(ResourcePublisher.ROLE); this.resourceDiscoverer = (ResourceDiscoverer) lookup(ResourceDiscoverer.ROLE); } /** * Concurrent publishing/consumption of resources * * @throws Exception */ public void testMultipleResourceExchange() throws Exception { final Set resourceSet = Collections.synchronizedSet(new TreeSet()); final Set foundResourceSet = new TreeSet(); AtomicBoolean doneFlag = new AtomicBoolean(false); Thread backCollector = new BackThread(resourceSet, foundResourceSet, doneFlag); backCollector.start(); int resourceCount = 0; Random rng = new Random(0); for (int i = 0; i < 16; i++) { DiscoverableResource discoverableResource = new DiscoverableResource(); discoverableResource.setId("test-server-" + i); discoverableResource.setName("Test Server " + i + " [" + StringUtils.leftPad(Integer.toHexString(rng.nextInt()) .toUpperCase(), 8, "0") + "]"); discoverableResource.setUrl(new URL("http://localhost:" + i + "/path?a=b&c+d=e&f=Hello%2C%20World%21&g&h=")); discoverableResource.setType("_http.tcp.local."); synchronized (backCollector) { this.resourcePublisher.registerResource(discoverableResource); if (LOGGER.isInfoEnabled()) LOGGER.info("producing(name=\"" + discoverableResource.getName() + "\")"); resourceSet.add(discoverableResource.getName()); } Thread.yield(); assertTrue("BackCollector should be running", backCollector .isAlive()); resourceCount++; } { long timeouts = 500L * resourceCount + System.currentTimeMillis(); do { if (foundResourceSet.size() == resourceCount) { doneFlag.set(true); break; } else { Thread.yield(); } } while (System.currentTimeMillis() < timeouts); } assertTrue("resourceSet should be empty", resourceSet.isEmpty()); assertFalse("foundResourceSet should not be empty", foundResourceSet .isEmpty()); assertEquals("resourceCount should equals foundResourceSet size", Integer.valueOf(foundResourceSet.size()), Integer .valueOf(resourceCount)); /** * Reset to defaults. Restart */ resourceSet.addAll(foundResourceSet); foundResourceSet.clear(); this.container.release(this.resourceDiscoverer); doneFlag.set(false); this.resourceDiscoverer = (ResourceDiscoverer) lookup(ResourceDiscoverer.ROLE); backCollector = new BackThread(resourceSet, foundResourceSet, doneFlag); backCollector.start(); { long timeouts = 5000L * resourceCount + System.currentTimeMillis(); do { if (foundResourceSet.size() == resourceCount) { doneFlag.set(true); break; } else { Thread.yield(); } Thread.sleep(500); } while (System.currentTimeMillis() < timeouts); } assertFalse("backCollector should not be running", backCollector.isAlive()); assertTrue("resourceSet should be empty", resourceSet.isEmpty()); assertFalse("foundResourceSet should not be empty", foundResourceSet .isEmpty()); assertEquals("resourceCount should equals foundResourceSet size", Integer.valueOf(foundResourceSet.size()), Integer .valueOf(resourceCount)); } }