@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()); }
@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; } });
public InternalCallContext createInternalCallContext(final Long accountRecordId, final InternalCallContext context) { final ImmutableAccountData immutableAccountData = getImmutableAccountData(accountRecordId, context.getTenantRecordId()); final DateTimeZone fixedOffsetTimeZone = immutableAccountData.getFixedOffsetTimeZone(); final DateTime referenceTime = immutableAccountData.getReferenceTime(); populateMDCContext(context.getUserToken(), accountRecordId, context.getTenantRecordId()); return new InternalCallContext(context, accountRecordId, fixedOffsetTimeZone, referenceTime, context.getCreatedDate()); }
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 OverdueChangeInternalEvent createOverdueEvent(final ImmutableAccountData overdueable, final String previousOverdueStateName, final String nextOverdueStateName, final boolean isBlockedBilling, final boolean isUnblockedBilling, final InternalCallContext context) throws BlockingApiException { return new DefaultOverdueChangeEvent(overdueable.getId(), previousOverdueStateName, nextOverdueStateName, isBlockedBilling, isUnblockedBilling, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()); }
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); } }
public InternalCallContext createInternalCallContext(final TimeZoneAwareEntity accountModelDao, final Long accountRecordId, final InternalCallContext context) { // See DefaultImmutableAccountData implementation final DateTimeZone fixedOffsetTimeZone = AccountDateTimeUtils.getFixedOffsetTimeZone(accountModelDao); final DateTime referenceTime = accountModelDao.getReferenceTime(); populateMDCContext(context.getUserToken(), accountRecordId, context.getTenantRecordId()); return new InternalCallContext(context, accountRecordId, fixedOffsetTimeZone, referenceTime, context.getCreatedDate()); }
public InternalCallContext(final InternalCallContext context, final Long accountRecordId, final DateTimeZone fixedOffsetTimeZone, final DateTime referenceDateTime, final DateTime utcNow) { this(context.getTenantRecordId(), accountRecordId, fixedOffsetTimeZone, referenceDateTime, context.getUserToken(), context.getCreatedBy(), context.getCallOrigin(), context.getContextUserType(), context.getReasonCode(), context.getComments(), utcNow, utcNow); }
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); } }
@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); } }
private void recordFutureNotificationFromTransaction(final EntitySqlDaoWrapperFactory transactionalDao, 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(null, effectiveDate, notificationKey, context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); } catch (final NoSuchNotificationQueue e) { throw new RuntimeException(e); } catch (final IOException e) { throw new RuntimeException(e); } }
@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); } }
private void verifyInternalCallContext(final InternalCallContext context) { Assert.assertEquals(context.getCallOrigin(), callContext.getCallOrigin()); Assert.assertEquals(context.getComments(), callContext.getComments()); Assert.assertTrue(context.getCreatedDate().compareTo(callContext.getCreatedDate()) >= 0); Assert.assertEquals(context.getReasonCode(), callContext.getReasonCode()); Assert.assertTrue(context.getUpdatedDate().compareTo(callContext.getUpdatedDate()) >= 0); Assert.assertEquals(context.getCreatedBy(), callContext.getUserName()); Assert.assertEquals(context.getUserToken(), callContext.getUserToken()); Assert.assertEquals(context.getContextUserType(), callContext.getUserType()); // Our test callcontext doesn't have a tenant id Assert.assertEquals(context.getTenantRecordId(), (Long) InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID); } }
public InternalCallContext(final InternalCallContext context, final DateTime updatedDate) { this(context.getTenantRecordId(), context.getAccountRecordId(), context.getFixedOffsetTimeZone(), context.getReferenceDateTime(), context.getUserToken(), context.getCreatedBy(), context.getCallOrigin(), context.getContextUserType(), context.getReasonCode(), context.getComments(), context.getCreatedDate(), updatedDate); }
@Override public void create(final AccountModelDao account, final InternalCallContext context) throws AccountApiException { super.create(account, context); try { final Long accountRecordId = getRecordId(account.getId(), context); final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID : context.getTenantRecordId(); eventBus.post(new DefaultAccountCreationEvent(new DefaultAccountData(account), account.getId(), accountRecordId, tenantRecordId, UUID.randomUUID())); } catch (final EventBusException ex) { Assert.fail(ex.toString()); } }
@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; } });
private void notifyBusOfEffectiveImmediateChange(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent immediateEvent, final int seqId, final InternalCallContext context) { try { final SubscriptionBaseTransitionData transition = subscription.getTransitionFromEvent(immediateEvent, seqId); final BusEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, subscription.getAlignStartDate(), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId()); eventBus.post(busEvent); } catch (final EventBusException e) { log.warn("Failed to post effective event for subscription " + subscription.getId(), e); } }
@Override public void update(final AccountModelDao account, final boolean treatNullValueAsReset, final InternalCallContext context) { super.update(account, context); final AccountModelDao currentAccount = getById(account.getId(), context); final Long accountRecordId = getRecordId(account.getId(), context); final long tenantRecordId = context == null ? InternalCallContextFactory.INTERNAL_TENANT_RECORD_ID : context.getTenantRecordId(); final AccountChangeInternalEvent changeEvent = new DefaultAccountChangeEvent(account.getId(), currentAccount, account, accountRecordId, tenantRecordId, UUID.randomUUID(), clock.getUTCNow()); if (changeEvent.hasChanges()) { try { eventBus.post(changeEvent); } catch (final EventBusException ex) { Assert.fail(ex.toString()); } } }