Search in sources :

Example 1 with NameAlreadyUsed

use of gov.sandia.NotifyMonitoringExt.NameAlreadyUsed in project ACS by ACS-Community.

the class NCSubscriber method createProxySupplier.

/**
	 * Creates the proxy supplier (push-style, for structured events) 
	 * that lives in the Notify server process, managed by the consumer admin object, and
	 * will later be connected to this client-side subscriber object.
	 * 
	 * @throws AcsJCORBAProblemEx If creation of the proxy supplier failed.
	 */
private StructuredProxyPushSupplier createProxySupplier() throws AcsJCORBAProblemEx {
    StructuredProxyPushSupplier ret = null;
    String errMsg = null;
    // will get assigned "a numeric identifier [...] that is unique among all proxy suppliers [the admin object] has created"
    IntHolder proxyIdHolder = new IntHolder();
    String randomizedClientName = null;
    try {
        ProxySupplier proxy = null;
        while (proxy == null) {
            // See the comments on Consumer#createConsumer() for a nice explanation of why this randomness is happening here
            randomizedClientName = Helper.createRandomizedClientName(clientName);
            try {
                proxy = sharedConsumerAdmin.obtain_named_notification_push_supplier(ClientType.STRUCTURED_EVENT, proxyIdHolder, randomizedClientName);
            } catch (NameAlreadyUsed e) {
            // Hopefully we won't run into this situation. Still, try to go on in the loop,
            // with a different client name next time.
            } catch (NameMapError e) {
                // Default to the unnamed version
                proxy = sharedConsumerAdmin.obtain_notification_push_supplier(ClientType.STRUCTURED_EVENT, proxyIdHolder);
            }
        }
        ret = StructuredProxyPushSupplierHelper.narrow(proxy);
    } catch (AdminLimitExceeded ex) {
        // See NC spec 3.4.15.10
        // If the number of consumers currently connected to the channel with which the target ConsumerAdmin object is associated 
        // exceeds the value of the MaxConsumers administrative property, the AdminLimitExceeded exception is raised.
        String limit = ex.admin_property_err.value.extract_string();
        errMsg = "NC '" + channelName + "' is configured for a maximum of " + limit + " subscribers, which does not allow this client to subscribe.";
    }
    if (ret != null) {
        LOG_NC_SupplierProxyCreation_OK.log(logger, proxyIdHolder.value, clientName, randomizedClientName, channelName, getNotificationFactoryName());
    } else {
        LOG_NC_SupplierProxyCreation_FAIL.log(logger, clientName, channelName, getNotificationFactoryName(), errMsg);
        AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx();
        ex2.setInfo("Failed to create proxy supplier on NC '" + channelName + "' for client '" + clientName + "': " + errMsg);
        throw ex2;
    }
    return ret;
}
Also used : AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx) NameMapError(gov.sandia.NotifyMonitoringExt.NameMapError) AdminLimitExceeded(org.omg.CosNotifyChannelAdmin.AdminLimitExceeded) IntHolder(org.omg.CORBA.IntHolder) ProxySupplier(org.omg.CosNotifyChannelAdmin.ProxySupplier) NameAlreadyUsed(gov.sandia.NotifyMonitoringExt.NameAlreadyUsed) StructuredProxyPushSupplier(org.omg.CosNotifyChannelAdmin.StructuredProxyPushSupplier)

Example 2 with NameAlreadyUsed

use of gov.sandia.NotifyMonitoringExt.NameAlreadyUsed in project ACS by ACS-Community.

the class NCPublisher method init.

/**
	 * Initializes NCPublisher
	 * @param namingService Naming service
	 * @throws AcsJException
	 *             There are literally dozens of CORBA exceptions that could be
	 *             thrown by the NCPublisher class. Instead, these are
	 *             converted into an ACS Error System exception for the
	 *             developer's convenience.
	 */
protected synchronized void init(NamingContext namingService) throws AcsJException {
    helper = new Helper(channelName, channelNotifyServiceDomainName, this.services, namingService);
    isTraceEventsEnabled = helper.getChannelProperties().isTraceEventsEnabled(this.channelName);
    // get the channel
    // @TODO: handle Corba TIMEOUT 
    channel = helper.getNotificationChannel(getNotificationFactoryName());
    // Corba NC spec about adminId: a unique identifier assigned by the target EventChannel instance that is unique among all 
    // SupplierAdmin instances currently associated with the channel.
    // We are currently not using it, but it could be logged to help with NC debugging.
    IntHolder adminIdHolder = new IntHolder();
    org.omg.CosNotifyChannelAdmin.SupplierAdmin supplierAdminBase = null;
    try {
        supplierAdminBase = channel.new_for_suppliers(InterFilterGroupOperator.AND_OP, adminIdHolder);
    } catch (TIMEOUT ex) {
        // found in http://jira.alma.cl/browse/COMP-6312
        throw new AcsJCORBAProblemEx(ex);
    }
    if (supplierAdminBase == null) {
        AcsJCORBAReferenceNilEx ex = new AcsJCORBAReferenceNilEx();
        ex.setVariable("supplierAdminBase");
        ex.setContext("Null reference obtained for the supplier admin for channel " + this.channelName);
        throw ex;
    }
    try {
        supplierAdmin = gov.sandia.NotifyMonitoringExt.SupplierAdminHelper.narrow(supplierAdminBase);
    } catch (BAD_PARAM ex) {
        // This should never happen, since we already enforced the presence of TAO extensions in Helper#initializeNotifyFactory
        String specialSupplierAdminId = gov.sandia.NotifyMonitoringExt.SupplierAdminHelper.id();
        String standardSupplierAdminId = org.omg.CosNotifyChannelAdmin.SupplierAdminHelper.id();
        LOG_NC_TaoExtensionsSubtypeMissing.log(logger, channelName + "-SupplierAdmin", specialSupplierAdminId, standardSupplierAdminId);
        AcsJNarrowFailedEx ex2 = new AcsJNarrowFailedEx(ex);
        ex2.setNarrowType(specialSupplierAdminId);
        throw ex2;
    }
    int proxyCreationAttempts = 0;
    while (proxyConsumer == null) {
        String randomizedClientName = Helper.createRandomizedClientName(services.getName());
        // Holder for the unique ID assigned by the admin object. It is different from the name we set, and will be discarded.
        IntHolder proxyIdHolder = new IntHolder();
        proxyCreationAttempts++;
        try {
            // Create the consumer proxy (to which the published events will be fed) with a name.
            // The client type parameter selects a StructuredProxyPushConsumer (based on Structured Events),
            // as opposed to ProxyPushConsumer (based on Anys), or SequenceProxyPushConsumer (based on sequences of Structured Events).
            org.omg.CORBA.Object tempCorbaObj = supplierAdmin.obtain_named_notification_push_consumer(ClientType.STRUCTURED_EVENT, proxyIdHolder, randomizedClientName.toString());
            if (tempCorbaObj == null) {
                AcsJCORBAReferenceNilEx ex = new AcsJCORBAReferenceNilEx();
                ex.setVariable("tempCorbaObj");
                ex.setContext("Null reference obtained for the Proxy Push Consumer for publisher " + services.getName());
                // @TODO destroy supplierAdmin
                throw ex;
            }
            proxyConsumer = StructuredProxyPushConsumerHelper.narrow(tempCorbaObj);
            LOG_NC_ConsumerProxyCreation_OK.log(logger, proxyIdHolder.value, randomizedClientName, proxyCreationAttempts, services.getName(), channelName, getNotificationFactoryName());
        } catch (NameAlreadyUsed e) {
            // Hopefully we won't run into this situation. Still, try to go on in the loop,
            // with a different client name next time.
            logger.fine("Consumer proxy name '" + randomizedClientName + "' already in use. Will try again with different random number appended.");
        } catch (NameMapError ex) {
            // Default to the unnamed version
            try {
                proxyConsumer = StructuredProxyPushConsumerHelper.narrow(supplierAdmin.obtain_notification_push_consumer(ClientType.STRUCTURED_EVENT, proxyIdHolder));
                LOG_NC_ConsumerProxyCreation_OK.log(logger, proxyIdHolder.value, "-unknown-", proxyCreationAttempts, services.getName(), channelName, getNotificationFactoryName());
            } catch (AdminLimitExceeded ex2) {
                LOG_NC_ConsumerProxyCreation_FAIL.log(logger, services.getName(), channelName, getNotificationFactoryName(), ex2.getMessage());
                // @TODO destroy supplierAdmin
                throw new AcsJCORBAProblemEx(ex2);
            }
        } catch (AdminLimitExceeded e) {
            LOG_NC_ConsumerProxyCreation_FAIL.log(logger, services.getName(), channelName, getNotificationFactoryName(), e.getMessage());
            // @TODO destroy supplierAdmin
            throw new AcsJCORBAProblemEx(e);
        }
    }
    // Avoid future calls from the NC to #subscription_change(EventType[], EventType[]). See Corba spec 3.4.1.3
    // @TODO: If we use ALL_NOW_UPDATES_ON then we could actually suppress sending of event types that no consumer wants to get. 
    proxyConsumer.obtain_subscription_types(ObtainInfoMode.NONE_NOW_UPDATES_OFF);
    // see 3.4.4.1 of Notification Service, v1.1
    try {
        StructuredPushSupplier thisSps = StructuredPushSupplierHelper.narrow(this.services.activateOffShoot(this));
        proxyConsumer.connect_structured_push_supplier(thisSps);
    } catch (AcsJContainerServicesEx e) {
        // @TODO destroy supplierAdmin and proxyConsumer
        throw new AcsJCORBAProblemEx(e);
    } catch (AlreadyConnected e) {
        // @TODO destroy supplierAdmin and proxyConsumer
        throw new AcsJCORBAProblemEx(e);
    }
    reconnectCallback = new AcsNcReconnectionCallback(this, logger);
    reconnectCallback.registerForReconnect(services, helper.getNotifyFactory());
}
Also used : StructuredPushSupplier(org.omg.CosNotifyComm.StructuredPushSupplier) AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx) AdminLimitExceeded(org.omg.CosNotifyChannelAdmin.AdminLimitExceeded) AlreadyConnected(org.omg.CosEventChannelAdmin.AlreadyConnected) BAD_PARAM(org.omg.CORBA.BAD_PARAM) AcsJContainerServicesEx(alma.JavaContainerError.wrappers.AcsJContainerServicesEx) EventDescriptionHelper(alma.acsnc.EventDescriptionHelper) StructuredProxyPushConsumerHelper(org.omg.CosNotifyChannelAdmin.StructuredProxyPushConsumerHelper) StructuredPushSupplierHelper(org.omg.CosNotifyComm.StructuredPushSupplierHelper) AcsJCORBAReferenceNilEx(alma.ACSErrTypeCORBA.wrappers.AcsJCORBAReferenceNilEx) NameMapError(gov.sandia.NotifyMonitoringExt.NameMapError) IntHolder(org.omg.CORBA.IntHolder) NameAlreadyUsed(gov.sandia.NotifyMonitoringExt.NameAlreadyUsed) TIMEOUT(org.omg.CORBA.TIMEOUT) AcsJNarrowFailedEx(alma.ACSErrTypeCORBA.wrappers.AcsJNarrowFailedEx)

Example 3 with NameAlreadyUsed

use of gov.sandia.NotifyMonitoringExt.NameAlreadyUsed in project ACS by ACS-Community.

the class Consumer method createConsumer.

/**
	 * Handles the CORBA creation of a consumer.
	 * Changed to private because only ctor of this class call this method as of Alma 5.0.2
	 * 
	 * @throws AcsJException
	 *            Any CORBA exceptions encountered are converted to an
	 *            AcsJException for developer's ease of use.
	 */
private void createConsumer() throws AcsJException {
    IntHolder consumerAdminIDHolder = new IntHolder();
    // get the Consumer admin object (no reuse of admin obj. This gets addressed in the new NCSubscriber class)
    // We don't need to use the TAO extension method "named_new_for_consumers" because only the proxy object will get a name from us.
    m_consumerAdmin = m_channel.new_for_consumers(InterFilterGroupOperator.AND_OP, consumerAdminIDHolder);
    // sanity check
    if (m_consumerAdmin == null) {
        String reason = "The '" + m_channelName + "' channel: null consumer admin";
        throw new alma.ACSErrTypeJavaNative.wrappers.AcsJJavaLangEx(reason);
    }
    // get the Supplier proxy
    proxyID = new IntHolder();
    gov.sandia.NotifyMonitoringExt.ConsumerAdmin consumerAdminExt = null;
    try {
        consumerAdminExt = gov.sandia.NotifyMonitoringExt.ConsumerAdminHelper.narrow(m_consumerAdmin);
    } catch (BAD_PARAM ex) {
    // Don't care, we won't be able to create the proxy with a name, but that's it
    // HSO: Actually this should never happen, because without TAO extension present, 
    // already getting the NotifyFactory reference would have failed.
    }
    if (consumerAdminExt != null) {
        // which could lead to memory leaks
        while (m_proxySupplier == null) {
            String randomizedClientName = m_helper.createRandomizedClientName(m_clientName);
            try {
                // Create the push supplier with a name
                m_proxySupplier = StructuredProxyPushSupplierHelper.narrow(consumerAdminExt.obtain_named_notification_push_supplier(ClientType.STRUCTURED_EVENT, proxyID, randomizedClientName));
                m_logger.fine("Created named proxy supplier '" + randomizedClientName + "'");
            } catch (NameAlreadyUsed e) {
            // Hopefully we won't run into this situation. Still, try to go on in the loop,
            // with a different client name next time.
            } catch (NameMapError e) {
                // Default to the unnamed version
                try {
                    m_proxySupplier = StructuredProxyPushSupplierHelper.narrow(m_consumerAdmin.obtain_notification_push_supplier(ClientType.STRUCTURED_EVENT, proxyID));
                } catch (AdminLimitExceeded e1) {
                    throw new AcsJCORBAProblemEx(e1);
                }
            } catch (AdminLimitExceeded e) {
                throw new AcsJCORBAProblemEx(e);
            }
        }
    } else {
        // Create the push supplier without a name
        try {
            m_proxySupplier = StructuredProxyPushSupplierHelper.narrow(m_consumerAdmin.obtain_notification_push_supplier(ClientType.STRUCTURED_EVENT, proxyID));
        } catch (org.omg.CosNotifyChannelAdmin.AdminLimitExceeded e) {
            // convert it into an exception developers care about
            throw new alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx(e);
        }
    }
    // sanity check
    if (m_proxySupplier == null) {
        String reason = "The '" + m_channelName + "' channel: null proxy supplier";
        throw new alma.ACSErrTypeJavaNative.wrappers.AcsJJavaLangEx(reason);
    }
    LOG_NC_SubscriptionConnect_OK.log(m_logger, m_channelName, m_notifyServiceName);
}
Also used : AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx) AdminLimitExceeded(org.omg.CosNotifyChannelAdmin.AdminLimitExceeded) BAD_PARAM(org.omg.CORBA.BAD_PARAM) NameMapError(gov.sandia.NotifyMonitoringExt.NameMapError) IntHolder(org.omg.CORBA.IntHolder) NameAlreadyUsed(gov.sandia.NotifyMonitoringExt.NameAlreadyUsed) AdminLimitExceeded(org.omg.CosNotifyChannelAdmin.AdminLimitExceeded) AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx)

Example 4 with NameAlreadyUsed

use of gov.sandia.NotifyMonitoringExt.NameAlreadyUsed in project ACS by ACS-Community.

the class HelperTest method testConcurrentChannelCreation.

/**
	 * Tests the collision case where many threads create the same channel concurrently.
	 * <p>
	 * Note that we would need to hack TAO to slow down (or otherwise synchronize with) channel creation,
	 * so that we can be sure that the second request comes in before the first request has finished.
	 * We optimize this by synchronizing the test threads right before they make the call to the channel factory, 
	 * for which we overload the method {@link HelperWithChannelCreationSynch#createNotifyChannel_internal(EventChannelFactory, Property[], Property[], String, IntHolder)}.
	 * This eliminates jitter from thread creation, thread starting, and contact with the naming service, all happening before actual channel creation.
	 */
public void testConcurrentChannelCreation() throws Exception {
    // one channel tried to be created concurrently
    final String channelName = "testChannelForConcurrentCreation";
    final HelperWithChannelCreationSynch helper = new HelperWithChannelCreationSynch(channelName, getContainerServices(), nctx);
    assertChannel(false, channelName);
    // @TODO Refactor the following code to use alma.acs.concurrent.ThreadBurstExecutorService now that we have it
    class ChannelCreator implements Callable<EventChannel> {

        private final CountDownLatch synchStart;

        ChannelCreator(CountDownLatch synchStart) {
            this.synchStart = synchStart;
        }

        public EventChannel call() throws Exception {
            String factoryName = helper.getNotificationFactoryNameForChannel();
            return helper.createNotificationChannel(NC_KIND.value, factoryName, synchStart);
        }
    }
    // we need at least two threads, but more threads may improve collision chances
    final int numCreators = 4;
    assertTrue(numCreators >= 2);
    ExecutorService pool = Executors.newFixedThreadPool(numCreators, getContainerServices().getThreadFactory());
    CountDownLatch synchCreationStart = new CountDownLatch(numCreators);
    List<Future<EventChannel>> results = new ArrayList<Future<EventChannel>>();
    // check the results
    EventChannel uniqueChannel = null;
    try {
        // Run the threads that create the same channel
        for (int i = 0; i < numCreators; i++) {
            results.add(pool.submit(new ChannelCreator(synchCreationStart)));
        }
        // wait for all threads to finish. Waiting here instead of waiting on the future.get() calls
        // has the advantage that we can exit this method with a fail() without leaving an ongoing channel creation behind.
        pool.shutdown();
        assertTrue(pool.awaitTermination(30, TimeUnit.SECONDS));
        for (Future<EventChannel> future : results) {
            try {
                EventChannel threadResult = future.get();
                // we only get here if threadResult != null, otherwise ex
                if (uniqueChannel != null) {
                    fail("Only one thread should have managed to create the channel without exception!");
                } else {
                    uniqueChannel = threadResult;
                }
            } catch (ExecutionException ex) {
                if (ex.getCause() instanceof NameAlreadyUsed) {
                    m_logger.info("Got a NameAlreadyUsed exception");
                } else {
                    fail("Unexpected exception " + ex.getCause().toString());
                }
            } catch (AssertionFailedError ex) {
                throw ex;
            } catch (Throwable thr) {
                fail("Unexpected exception " + thr.toString());
            }
        }
        assertNotNull("One thread should have succeeded", uniqueChannel);
    } finally {
        if (uniqueChannel != null) {
            helper.destroyNotificationChannel(NC_KIND.value, uniqueChannel);
        }
    }
}
Also used : ArrayList(java.util.ArrayList) CountDownLatch(java.util.concurrent.CountDownLatch) Callable(java.util.concurrent.Callable) EventChannel(gov.sandia.NotifyMonitoringExt.EventChannel) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) NameAlreadyUsed(gov.sandia.NotifyMonitoringExt.NameAlreadyUsed) ExecutionException(java.util.concurrent.ExecutionException) AssertionFailedError(junit.framework.AssertionFailedError)

Example 5 with NameAlreadyUsed

use of gov.sandia.NotifyMonitoringExt.NameAlreadyUsed in project ACS by ACS-Community.

the class Helper method getNotificationChannel.

/**
	 * This method gets a reference to the event channel. If it is not already
	 * registered with the naming service, it is created.
	 * 
	 * @return Reference to the event channel specified by channelName. Never null.
	 * @param channelKind
	 *           Kind of the channel as registered with the CORBA naming service ("channels").
	 * @param notifyFactoryName
	 *           Name of the notification service as registered with the CORBA
	 *           naming service.
	 * @throws AcsJException
	 *            Standard ACS Java exception.
	 */
protected EventChannel getNotificationChannel(String notifyFactoryName) throws AcsJException {
    String channelKind = NC_KIND.value;
    // return value
    EventChannel retValue = null;
    NameComponent[] t_NameSequence = { new NameComponent(combineChannelAndDomainName(channelName, domainName), channelKind) };
    // (retryNumberAttempts * retrySleepSec) = the time before we give up to get a reference or create the channel if 
    // a channel of the given name supposedly gets created already (due to race conditions with other clients).
    int retryNumberAttempts = 20;
    int retrySleepSec = 2;
    do {
        try {
            // @TODO move the check for existing channel from naming service to the NC factory,
            // now that we use the TAO extension with named NCs.
            // The only advantage of still using the naming service is that the naming service is a real system-wide singleton
            // and can return also channels that were by mistake created from a different notify service factory than the one configured in the CDB.
            initializeNotifyFactory(notifyFactoryName);
            retValue = EventChannelHelper.narrow(getNamingService().resolve(t_NameSequence));
        } catch (org.omg.CosNaming.NamingContextPackage.NotFound e) {
        // No other consumers or suppliers have registered the channel yet...
        // This can mean that the channel has never been created, or that it is currently being created but has not yet been registered.
        } catch (org.omg.CosNaming.NamingContextPackage.CannotProceed e) {
            // Think there is virtually no chance of this every happening but...
            throw new AcsJUnexpectedExceptionEx(e);
        } catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) {
            // Think there is virtually no chance of this every happening but...
            throw new AcsJUnexpectedExceptionEx(e);
        }
        if (retValue == null) {
            // but only because we use the TAO extensions that support named NCs.
            try {
                retValue = createNotificationChannel(channelKind, notifyFactoryName);
            } catch (NameAlreadyUsed ex) {
                m_logger.log(Level.INFO, "NC '" + channelName + "' seems to be getting created. Will wait and try again in " + retrySleepSec + " seconds.", ex);
                try {
                    Thread.sleep(retrySleepSec * 1000);
                } catch (InterruptedException ex1) {
                // too bad
                }
            }
        } else // The channel could be resolved from the Naming Service
        {
            // Get the channel timestamp located into the Naming Service or set it to the current time
            initChannelTimestamp();
        //				System.out.println("*** Got NC " + channelName + " from the naming service");
        }
    } while (retValue == null && --retryNumberAttempts >= 0);
    if (retValue == null) {
        AcsJGenericErrorEx ex = new AcsJGenericErrorEx();
        ex.setErrorDesc("Giving up to get reference to channel " + channelName);
        throw ex;
    }
    return retValue;
}
Also used : AcsJGenericErrorEx(alma.ACSErrTypeCommon.wrappers.AcsJGenericErrorEx) NameComponent(org.omg.CosNaming.NameComponent) EventChannel(gov.sandia.NotifyMonitoringExt.EventChannel) AcsJUnexpectedExceptionEx(alma.ACSErrTypeCommon.wrappers.AcsJUnexpectedExceptionEx) NameAlreadyUsed(gov.sandia.NotifyMonitoringExt.NameAlreadyUsed)

Aggregations

NameAlreadyUsed (gov.sandia.NotifyMonitoringExt.NameAlreadyUsed)5 AcsJCORBAProblemEx (alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx)3 NameMapError (gov.sandia.NotifyMonitoringExt.NameMapError)3 IntHolder (org.omg.CORBA.IntHolder)3 AdminLimitExceeded (org.omg.CosNotifyChannelAdmin.AdminLimitExceeded)3 EventChannel (gov.sandia.NotifyMonitoringExt.EventChannel)2 BAD_PARAM (org.omg.CORBA.BAD_PARAM)2 AcsJCORBAReferenceNilEx (alma.ACSErrTypeCORBA.wrappers.AcsJCORBAReferenceNilEx)1 AcsJNarrowFailedEx (alma.ACSErrTypeCORBA.wrappers.AcsJNarrowFailedEx)1 AcsJGenericErrorEx (alma.ACSErrTypeCommon.wrappers.AcsJGenericErrorEx)1 AcsJUnexpectedExceptionEx (alma.ACSErrTypeCommon.wrappers.AcsJUnexpectedExceptionEx)1 AcsJContainerServicesEx (alma.JavaContainerError.wrappers.AcsJContainerServicesEx)1 EventDescriptionHelper (alma.acsnc.EventDescriptionHelper)1 ArrayList (java.util.ArrayList)1 Callable (java.util.concurrent.Callable)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 ExecutionException (java.util.concurrent.ExecutionException)1 ExecutorService (java.util.concurrent.ExecutorService)1 Future (java.util.concurrent.Future)1 AssertionFailedError (junit.framework.AssertionFailedError)1