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;
}
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());
}
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);
}
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);
}
}
}
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;
}
Aggregations