Search in sources :

Example 1 with EventChannel

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

the class Helper method createNotificationChannel.

/**
	 * Tries to create a notification channel (using quality of service and administrative properties 
	 * specified by configQofS() and configAdminProps() respectively).
	 * If this succeeds, then registers this channel with the naming service.
	 * <p>
	 * Should only be invoked when the channel that this supplier or consumer is attempting to connect to
	 * does not exist.
	 * However even with prior check for the existence of this channel, a race condition with other suppliers or consumers
	 * can lead to multiple attempts to create the same channel, which will result in <code>NameAlreadyUsed</code> exception.
	 * <p>
	 * Design note: Currently the TAO notification extensions are used to synch channel creation with other clients
	 * by supplying the channel name to the factory.
	 * If we want to use only standard NC factories then we'd have to implement our own locking mechanisms in all 
	 * ACS consumer and supplier classes, see http://jira.alma.cl/browse/COMP-2808
	 * 
	 * @return Reference to the newly created channel.
	 * @param channelKind
	 *           Kind of the channel as registered with the CORBA naming service.
	 * @param notifyFactoryName
	 *           Name of the notification service as registered with the CORBA naming service.
	 * @throws AcsJException
	 *            Standard ACS Java exception.
	 * @throws NameAlreadyUsed thrown if the channel of this name already exists.
	 */
protected EventChannel createNotificationChannel(String channelKind, String notifyFactoryName) throws AcsJException, NameAlreadyUsed {
    LOG_NC_ChannelCreated_ATTEMPT.log(m_logger, channelName, notifyFactoryName);
    // return value
    EventChannel retValue = null;
    // to be assigned by factory
    channelId = -1;
    StopWatch stopwatch = new StopWatch();
    try {
        initializeNotifyFactory(notifyFactoryName);
        // create the channel
        // here we use the channel properties taken directly from our channel properties helper object. 
        // presumably these values come from the ACS configuration database.
        IntHolder channelIdHolder = new IntHolder();
        retValue = createNotifyChannel_internal(m_channelProperties.configQofS(channelName), m_channelProperties.configAdminProps(channelName), channelIdHolder);
        // sanity check
        if (retValue == null) {
            // a null reference implies we cannot go any further
            Throwable cause = new Throwable("Null reference obtained for the '" + channelName + "' channel!");
            // TODO: more specific ex type
            throw new alma.ACSErrTypeJavaNative.wrappers.AcsJJavaLangEx(cause);
        }
        channelId = channelIdHolder.value;
        // register our new channel with the naming service
        try {
            NameComponent[] t_NameChannel = { new NameComponent(combineChannelAndDomainName(channelName, domainName), channelKind) };
            getNamingService().rebind(t_NameChannel, retValue);
            // Create an entry into the Naming Service to store the timestamp of the channel in order to allow
            // subscribers to reconnect to the channel (ICT-4730)
            int maxNumAttempts = 10;
            int nAttempts = maxNumAttempts;
            boolean timestampCreated = setChannelTimestamp(retValue);
            while (false == timestampCreated && nAttempts > 0) {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex1) {
                // too bad
                }
                nAttempts--;
                timestampCreated = setChannelTimestamp(retValue);
            }
            if (false == timestampCreated) {
                Throwable cause = new Throwable("Failed to register the timestamp of the channel '" + channelName + "' into the Naming Service after " + String.valueOf(maxNumAttempts) + " attempts");
                // TODO: more specific ex type
                throw new alma.ACSErrTypeJavaNative.wrappers.AcsJJavaLangEx(cause);
            }
        } catch (org.omg.CosNaming.NamingContextPackage.NotFound ex) {
            // Corba spec: "If already bound, the previous binding must be of type nobject; 
            //              otherwise, a NotFound exception with a why reason of not_object is raised."
            String reason = "Failed to register the new channel '" + channelName + "' with the Naming Service: " + ex.why.toString();
            AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(ex);
            ex2.setInfo(reason);
            throw ex2;
        }
    } catch (org.omg.CosNaming.NamingContextPackage.CannotProceed e) {
        // Think there is virtually no chance of this every happening but...
        Throwable cause = new Throwable(e.getMessage());
        throw new alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx(cause);
    } catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) {
        // Think there is virtually no chance of this every happening but...
        Throwable cause = new Throwable(e.getMessage());
        throw new alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx(cause);
    } catch (org.omg.CosNotification.UnsupportedQoS e) {
        Throwable cause = new Throwable("The quality of service properties specified for the '" + channelName + "' channel are unsupported: " + e.getMessage());
        throw new alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx(cause);
    }
    LOG_NC_ChannelCreated_OK.log(m_logger, channelName, channelId, notifyFactoryName, stopwatch.getLapTimeMillis());
    return retValue;
}
Also used : AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx) NameComponent(org.omg.CosNaming.NameComponent) UnsupportedQoS(org.omg.CosNotification.UnsupportedQoS) StopWatch(alma.acs.util.StopWatch) EventChannel(gov.sandia.NotifyMonitoringExt.EventChannel) IntHolder(org.omg.CORBA.IntHolder) AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx)

Example 2 with EventChannel

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

the class HelperTest method testCreateChannel.

/**
	 * Creates and destroys a test channel.
	 * Also tests creating a second instance of that channel after the first one has been created, 
	 * to check for the NameAlreadyUsed ex.
	 */
public void testCreateChannel() throws Exception {
    String channelName = "singleChannel";
    Helper helper = new HelperWithChannelCreationSynch(channelName, getContainerServices(), nctx);
    String factoryName = helper.getNotificationFactoryNameForChannel();
    EventChannel myChannel = null;
    try {
        //precondition: channel not there (e.g. from previous run)
        assertChannel(false, channelName);
        // The call to "getNotificationChannel" should create the channel, because reuse will not be possible.
        myChannel = helper.getNotificationChannel(factoryName);
        assertChannel(true, channelName);
        // Now we try to create that channel again, without allowing reuse. Should fail. 
        try {
            helper.createNotificationChannel(NC_KIND.value, factoryName);
            fail("Expected NameAlreadyUsed exception for creating the channel twice.");
        } catch (Exception ex) {
            m_logger.info("Got a NameAlreadyUsed exception as expected.");
        }
        // But with reuse it should work
        EventChannel myChannel2 = helper.getNotificationChannel(factoryName);
        assertTrue(myChannel._is_equivalent(myChannel2));
    } finally {
        // Destroy the channel
        if (myChannel != null) {
            helper.destroyNotificationChannel(NC_KIND.value, myChannel);
        }
        assertChannel(false, channelName);
    }
}
Also used : NamingContextHelper(org.omg.CosNaming.NamingContextHelper) NotificationServiceMonitorControlHelper(gov.sandia.CosNotification.NotificationServiceMonitorControlHelper) EventChannel(gov.sandia.NotifyMonitoringExt.EventChannel) ExecutionException(java.util.concurrent.ExecutionException) AcsJException(alma.acs.exceptions.AcsJException)

Example 3 with EventChannel

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

the class HelperTest method testConcurrentChannelRetrieval.

/**
	 * One step up from {@link #testConcurrentChannelCreation()}, here we test concurrent calls to 
	 * {@link Helper#getNotificationChannel(String, String, String)} which are supposed to handle the 
	 * <code>NameAlreadyUsed</code> exception by making those later threads wait until the channel has 
	 * been created for the first thread, then sharing the channel object.
	 */
public void testConcurrentChannelRetrieval() throws Throwable {
    // one channel to be retrieved concurrently
    final String channelName = "testChannelForConcurrentRetrieval";
    final HelperWithChannelCreationSynch helper = new HelperWithChannelCreationSynch(channelName, getContainerServices(), nctx);
    assertChannel(false, channelName);
    class ChannelRetriever implements Callable<EventChannel> {

        private final CountDownLatch synchStart;

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

        public EventChannel call() throws Exception {
            String factoryName = helper.getNotificationFactoryNameForChannel();
            return helper.getNotificationChannel(factoryName, synchStart);
        }
    }
    // we need at least two threads, but more threads may improve collision chances
    final int numCreators = 3;
    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 request the same channel
        for (int i = 0; i < numCreators; i++) {
            results.add(pool.submit(new ChannelRetriever(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) {
                    assertTrue(uniqueChannel._is_equivalent(threadResult));
                }
                uniqueChannel = threadResult;
            } catch (ExecutionException ex) {
                throw ex.getCause();
            } catch (AssertionFailedError ex) {
                throw ex;
            } catch (Throwable thr) {
                fail("Unexpected exception " + thr.toString());
            }
        }
        m_logger.info("All concurrent calls to getNotificationChannel got the same channel object.");
    } 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) ExecutionException(java.util.concurrent.ExecutionException) AssertionFailedError(junit.framework.AssertionFailedError)

Example 4 with EventChannel

use of gov.sandia.NotifyMonitoringExt.EventChannel 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 EventChannel

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

the class Helper method createNotifyChannel_internal.

/**
	 * Broken out from {@link #createNotificationChannel(String, String, String)}
	 * to give tests better control about the timing when this call to the event factory is made.
	 * @throws NameAlreadyUsed if the call to NotifyFactory#create_named_channel fails with this exception.
	 * @throws AcsJCORBAProblemEx if the TAO extension throws a NameMapError or if the QoS attributes cause a UnsupportedAdmin.
	 */
protected EventChannel createNotifyChannel_internal(Property[] initial_qos, Property[] initial_admin, IntHolder channelIdHolder) throws NameAlreadyUsed, UnsupportedQoS, AcsJNarrowFailedEx, AcsJCORBAProblemEx {
    EventChannel ret = null;
    StopWatch stopwatch = new StopWatch();
    try {
        // The TAO extension of the notify factory that we use declares only the plain EventChannel type, 
        // even though it creates the TAO-extension subtype.
        org.omg.CosNotifyChannelAdmin.EventChannel eventChannelBaseType = notifyFactory.create_named_channel(initial_qos, initial_admin, channelIdHolder, channelName);
        LOG_NC_ChannelCreatedRaw_OK.log(m_logger, channelName, channelIdHolder.value, stopwatch.getLapTimeMillis());
        // re-create the client side corba stub, to get the extension subtype
        ret = gov.sandia.NotifyMonitoringExt.EventChannelHelper.narrow(eventChannelBaseType);
    } catch (BAD_PARAM ex) {
        LOG_NC_TaoExtensionsSubtypeMissing.log(m_logger, channelName, EventChannel.class.getName(), org.omg.CosNotifyChannelAdmin.EventChannelHelper.id());
        AcsJNarrowFailedEx ex2 = new AcsJNarrowFailedEx(ex);
        ex2.setNarrowType(EventChannelHelper.id());
        throw ex2;
    } catch (NameMapError ex) {
        String msg = "Got a TAO extension-specific NameMapError exception that means the TAO NC extension is not usable. Bailing out since we need the extension.";
        m_logger.log(AcsLogLevel.ERROR, msg, ex);
        AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(ex);
        ex2.setInfo(msg);
        throw ex2;
    } catch (UnsupportedAdmin ex) {
        AcsJCORBAProblemEx ex2 = new AcsJCORBAProblemEx(ex);
        ex2.setInfo(createUnsupportedAdminLogMessage(ex));
        throw ex2;
    }
    return ret;
}
Also used : EventChannel(gov.sandia.NotifyMonitoringExt.EventChannel) AcsJCORBAProblemEx(alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx) NameMapError(gov.sandia.NotifyMonitoringExt.NameMapError) BAD_PARAM(org.omg.CORBA.BAD_PARAM) AcsJNarrowFailedEx(alma.ACSErrTypeCORBA.wrappers.AcsJNarrowFailedEx) UnsupportedAdmin(org.omg.CosNotification.UnsupportedAdmin) StopWatch(alma.acs.util.StopWatch)

Aggregations

EventChannel (gov.sandia.NotifyMonitoringExt.EventChannel)6 ExecutionException (java.util.concurrent.ExecutionException)3 AcsJCORBAProblemEx (alma.ACSErrTypeCommon.wrappers.AcsJCORBAProblemEx)2 StopWatch (alma.acs.util.StopWatch)2 NameAlreadyUsed (gov.sandia.NotifyMonitoringExt.NameAlreadyUsed)2 ArrayList (java.util.ArrayList)2 Callable (java.util.concurrent.Callable)2 CountDownLatch (java.util.concurrent.CountDownLatch)2 ExecutorService (java.util.concurrent.ExecutorService)2 Future (java.util.concurrent.Future)2 AssertionFailedError (junit.framework.AssertionFailedError)2 NameComponent (org.omg.CosNaming.NameComponent)2 AcsJNarrowFailedEx (alma.ACSErrTypeCORBA.wrappers.AcsJNarrowFailedEx)1 AcsJGenericErrorEx (alma.ACSErrTypeCommon.wrappers.AcsJGenericErrorEx)1 AcsJUnexpectedExceptionEx (alma.ACSErrTypeCommon.wrappers.AcsJUnexpectedExceptionEx)1 AcsJException (alma.acs.exceptions.AcsJException)1 NotificationServiceMonitorControlHelper (gov.sandia.CosNotification.NotificationServiceMonitorControlHelper)1 NameMapError (gov.sandia.NotifyMonitoringExt.NameMapError)1 BAD_PARAM (org.omg.CORBA.BAD_PARAM)1 IntHolder (org.omg.CORBA.IntHolder)1