@Override public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception { final Iterable<NotificationEventWithMetadata<T>> futureNotifications = getFutureNotificationsForAccountInTransaction(entitySqlDaoWrapperFactory, checkOverdueQueue, clazz, context); final Iterator<NotificationEventWithMetadata<T>> iterator = futureNotifications.iterator(); try { while (iterator.hasNext()) { final NotificationEventWithMetadata<T> notification = iterator.next(); checkOverdueQueue.removeNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), notification.getRecordId()); } } finally { // Go through all results to close the connection while (iterator.hasNext()) { iterator.next(); } } return null; } });
@Override public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception { // Check if we already have notifications for that key final Class<T> clazz = (Class<T>) notificationKey.getClass(); final Iterable<NotificationEventWithMetadata<T>> futureNotifications = getFutureNotificationsForAccountInTransaction(entitySqlDaoWrapperFactory, overdueQueue, clazz, context); final boolean shouldInsertNewNotification = cleanupFutureNotificationsFormTransaction(entitySqlDaoWrapperFactory, futureNotifications, futureNotificationTime, overdueQueue); if (shouldInsertNewNotification) { log.debug("Queuing overdue check notification. Account id: {}, timestamp: {}", accountId.toString(), futureNotificationTime.toString()); overdueQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), futureNotificationTime, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); } else { log.debug("Skipping queuing overdue check notification. Account id: {}, timestamp: {}", accountId.toString(), futureNotificationTime.toString()); } return null; } });
@VisibleForTesting <T extends OverdueCheckNotificationKey> Iterable<NotificationEventWithMetadata<T>> getFutureNotificationsForAccountInTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final NotificationQueue checkOverdueQueue, final Class<T> clazz, final InternalCallContext context) { return checkOverdueQueue.getFutureNotificationFromTransactionForSearchKeys(context.getAccountRecordId(), context.getTenantRecordId(), entitySqlDaoWrapperFactory.getHandle().getConnection()); }
overdueQueue.removeNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), cur.getRecordId());
private void recordFutureNotificationFromTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final DateTime effectiveDate, final NotificationEvent notificationKey, final InternalCallContext context) { try { final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(KILLBILL_SERVICES.SUBSCRIPTION_BASE_SERVICE.getServiceName(), DefaultSubscriptionBaseService.NOTIFICATION_QUEUE_NAME); subscriptionEventQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), effectiveDate, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); } catch (final NoSuchNotificationQueue e) { throw new RuntimeException(e); } catch (final IOException e) { throw new RuntimeException(e); } }
private void notifyBusOfRequestedChange(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent nextEvent, final SubscriptionBaseTransitionType transitionType, final InternalCallContext context) { try { eventBus.postFromTransaction(new DefaultRequestedSubscriptionEvent(subscription, nextEvent, transitionType, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()), entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.warn("Failed to post requested change event for subscriptionId='{}'", subscription.getId(), e); } }
@Override public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws EntityPersistenceException, EventBusException { final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class); final AccountModelDao currentAccount = transactional.getById(accountId.toString(), context); if (currentAccount == null) { throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId); } // Check if an update is really needed. If not, bail early to avoid sending an extra event on the bus if ((currentAccount.getPaymentMethodId() == null && paymentMethodId == null) || (currentAccount.getPaymentMethodId() != null && currentAccount.getPaymentMethodId().equals(paymentMethodId))) { return null; } final String thePaymentMethodId = paymentMethodId != null ? paymentMethodId.toString() : null; final AccountModelDao account = (AccountModelDao) transactional.updatePaymentMethod(accountId.toString(), thePaymentMethodId, context); final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, currentAccount, account, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken(), context.getCreatedDate()); try { eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.warn("Failed to post account change event for accountId='{}'", accountId, e); } return null; } });
private void notifyBusOfEffectiveImmediateChange(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent immediateEvent, final int seqId, final InternalCallContext context) { try { final SubscriptionBaseTransitionData transition = subscription.getTransitionFromEvent(immediateEvent, seqId); if (transition != null) { final BusEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, subscription.getAlignStartDate(), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); eventBus.postFromTransaction(busEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } } catch (final EventBusException e) { log.warn("Failed to post effective event for subscriptionId='{}'", subscription.getId(), e); } }
@Override protected void postBusEventFromTransaction(final AccountModelDao account, final AccountModelDao savedAccount, final ChangeType changeType, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context) throws BillingExceptionBase { // This is only called for the create call (see update below) switch (changeType) { case INSERT: break; default: return; } final Long recordId = savedAccount.getRecordId(); // We need to re-hydrate the callcontext with the account record id final InternalCallContext rehydratedContext = internalCallContextFactory.createInternalCallContext(savedAccount, recordId, context); final AccountCreationInternalEvent creationEvent = new DefaultAccountCreationEvent(new DefaultAccountData(savedAccount), savedAccount.getId(), rehydratedContext.getAccountRecordId(), rehydratedContext.getTenantRecordId(), rehydratedContext.getUserToken()); try { eventBus.postFromTransaction(creationEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.warn("Failed to post account creation event for accountId='{}'", savedAccount.getId(), e); } }
@Override public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws EventBusException, AccountApiException { final AccountSqlDao transactional = entitySqlDaoWrapperFactory.become(AccountSqlDao.class); final UUID accountId = specifiedAccount.getId(); final AccountModelDao currentAccount = transactional.getById(accountId.toString(), context); if (currentAccount == null) { throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId); } specifiedAccount.validateAccountUpdateInput(currentAccount, treatNullValueAsReset); if (!treatNullValueAsReset) { // Set unspecified (null) fields to their current values specifiedAccount.mergeWithDelegate(currentAccount); } transactional.update(specifiedAccount, context); final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(accountId, currentAccount, specifiedAccount, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken(), context.getCreatedDate()); try { eventBus.postFromTransaction(changeEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.warn("Failed to post account change event for accountId='{}'", accountId, e); } return null; } });
@Override protected void postBusEventFromTransaction(final CustomFieldModelDao customField, final CustomFieldModelDao savedCustomField, final ChangeType changeType, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context) throws BillingExceptionBase { BusInternalEvent customFieldEvent = null; switch (changeType) { case INSERT: customFieldEvent = new DefaultCustomFieldCreationEvent(customField.getId(), customField.getObjectId(), customField.getObjectType(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); break; case DELETE: customFieldEvent = new DefaultCustomFieldDeletionEvent(customField.getId(), customField.getObjectId(), customField.getObjectType(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); break; default: return; } try { bus.postFromTransaction(customFieldEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final PersistentBus.EventBusException e) { log.warn("Failed to post tag event for customFieldId='{}'", customField.getId().toString(), e); } }
@Override public TagDefinitionModelDao inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception { final TagDefinitionSqlDao tagDefinitionSqlDao = entitySqlDaoWrapperFactory.become(TagDefinitionSqlDao.class); // Make sure the tag definition doesn't exist already final TagDefinitionModelDao existingDefinition = tagDefinitionSqlDao.getByName(definitionName, context); if (existingDefinition != null) { throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_ALREADY_EXISTS, definitionName); } // Create it final TagDefinitionModelDao tagDefinition = new TagDefinitionModelDao(context.getCreatedDate(), definitionName, description, tagDefinitionObjectTypes); createAndRefresh(tagDefinitionSqlDao, tagDefinition, context); // Post an event to the bus final boolean isControlTag = TagModelDaoHelper.isControlTag(tagDefinition.getName()); final TagDefinitionInternalEvent tagDefinitionEvent; if (isControlTag) { tagDefinitionEvent = tagEventBuilder.newControlTagDefinitionCreationEvent(tagDefinition.getId(), tagDefinition, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); } else { tagDefinitionEvent = tagEventBuilder.newUserTagDefinitionCreationEvent(tagDefinition.getId(), tagDefinition, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); } try { bus.postFromTransaction(tagDefinitionEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final PersistentBus.EventBusException e) { log.warn("Failed to post tag definition creation event for tagDefinitionId='{}'", tagDefinition.getId(), e); } return tagDefinition; } });
protected void postBusEventFromTransaction(final TagDefinitionModelDao tagDefinition, final TagDefinitionModelDao savedTagDefinition, final ChangeType changeType, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context) throws BillingExceptionBase { final TagDefinitionInternalEvent tagDefinitionEvent; final boolean isControlTag = TagModelDaoHelper.isControlTag(tagDefinition.getName()); switch (changeType) { case INSERT: tagDefinitionEvent = (isControlTag) ? tagEventBuilder.newControlTagDefinitionCreationEvent(tagDefinition.getId(), tagDefinition, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()) : tagEventBuilder.newUserTagDefinitionCreationEvent(tagDefinition.getId(), tagDefinition, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); break; case DELETE: tagDefinitionEvent = (isControlTag) ? tagEventBuilder.newControlTagDefinitionDeletionEvent(tagDefinition.getId(), tagDefinition, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()) : tagEventBuilder.newUserTagDefinitionDeletionEvent(tagDefinition.getId(), tagDefinition, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); break; default: return; } try { bus.postFromTransaction(tagDefinitionEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final PersistentBus.EventBusException e) { log.warn("Failed to post tag definition event for tagDefinitionId='{}'", tagDefinition.getId().toString(), e); } }
bus.postFromTransaction(tagEvent, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final PersistentBus.EventBusException e) { log.warn("Failed to post tag event for tagId='{}'", tag.getId().toString(), e);
@Override public Void inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception { // Check if we already have notifications for that key final Class<T> clazz = (Class<T>) notificationKey.getClass(); final Iterable<NotificationEventWithMetadata<T>> futureNotifications = getFutureNotificationsForAccountInTransaction(entitySqlDaoWrapperFactory, overdueQueue, clazz, context); final boolean shouldInsertNewNotification = cleanupFutureNotificationsFormTransaction(entitySqlDaoWrapperFactory, futureNotifications, futureNotificationTime, overdueQueue); if (shouldInsertNewNotification) { log.debug("Queuing overdue check notification. Account id: {}, timestamp: {}", accountId.toString(), futureNotificationTime.toString()); overdueQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), futureNotificationTime, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); } else { log.debug("Skipping queuing overdue check notification. Account id: {}, timestamp: {}", accountId.toString(), futureNotificationTime.toString()); } return null; } });
@VisibleForTesting <T extends OverdueCheckNotificationKey> Iterable<NotificationEventWithMetadata<T>> getFutureNotificationsForAccountInTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final NotificationQueue checkOverdueQueue, final Class<T> clazz, final InternalCallContext context) { return checkOverdueQueue.getFutureNotificationFromTransactionForSearchKeys(context.getAccountRecordId(), context.getTenantRecordId(), entitySqlDaoWrapperFactory.getHandle().getConnection()); }
private void notifyBusOfInvoiceAdjustment(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final UUID invoiceId, final UUID accountId, final UUID userToken, final InternalCallContext context) { try { eventBus.postFromTransaction(new DefaultInvoiceAdjustmentEvent(invoiceId, accountId, context.getAccountRecordId(), context.getTenantRecordId(), userToken), entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.warn("Failed to post adjustment event for invoiceId='{}'", invoiceId, e); } }
private void recordFutureNotificationFromTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final DateTime effectiveDate, final NotificationEvent notificationKey, final InternalCallContext context) { try { final NotificationQueue subscriptionEventQueue = notificationQueueService.getNotificationQueue(KILLBILL_SERVICES.SUBSCRIPTION_BASE_SERVICE.getServiceName(), DefaultSubscriptionBaseService.NOTIFICATION_QUEUE_NAME); subscriptionEventQueue.recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory.getHandle().getConnection(), effectiveDate, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); } catch (final NoSuchNotificationQueue e) { throw new RuntimeException(e); } catch (final IOException e) { throw new RuntimeException(e); } }
private void notifyBusOfRequestedChange(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent nextEvent, final SubscriptionBaseTransitionType transitionType, final InternalCallContext context) { try { eventBus.postFromTransaction(new DefaultRequestedSubscriptionEvent(subscription, nextEvent, transitionType, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()), entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.warn("Failed to post requested change event for subscriptionId='{}'", subscription.getId(), e); } }
private void notifyBusOfInvoiceCreation(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InvoiceModelDao invoice, final InternalCallContext context) { try { // This is called for a new COMMITTED invoice (which cannot be writtenOff as it does not exist yet, so rawBalance == balance) final BigDecimal rawBalance = InvoiceModelDaoHelper.getRawBalanceForRegularInvoice(invoice); final DefaultInvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(), rawBalance, invoice.getCurrency(), context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); eventBus.postFromTransaction(event, entitySqlDaoWrapperFactory.getHandle().getConnection()); } catch (final EventBusException e) { log.error(String.format("Failed to post invoice creation event %s for account %s", invoice.getAccountId()), e); } }