/*
* Copyright 2010-2013 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package org.killbill.billing.subscription.api.timeline;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import org.joda.time.DateTime;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.CatalogApiException;
import org.killbill.billing.catalog.api.CatalogService;
import org.killbill.billing.subscription.api.SubscriptionApiBase;
import org.killbill.billing.subscription.api.SubscriptionBase;
import org.killbill.billing.subscription.api.SubscriptionBaseApiService;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBase;
import org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle;
import org.killbill.billing.subscription.api.user.SubscriptionBaseBundle;
import org.killbill.billing.subscription.engine.dao.SubscriptionDao;
import org.killbill.billing.subscription.events.SubscriptionBaseEvent;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.clock.Clock;
import com.google.common.collect.ImmutableList;
import com.google.inject.Inject;
public class DefaultSubscriptionBaseTimelineApi extends SubscriptionApiBase implements SubscriptionBaseTimelineApi {
private final CatalogService catalogService;
private final InternalCallContextFactory internalCallContextFactory;
@Inject
public DefaultSubscriptionBaseTimelineApi(final CatalogService catalogService,
final SubscriptionBaseApiService apiService,
final SubscriptionDao dao,
final InternalCallContextFactory internalCallContextFactory,
final Clock clock) {
super(dao, apiService, clock, catalogService);
this.catalogService = catalogService;
this.internalCallContextFactory = internalCallContextFactory;
}
@Override
public BundleBaseTimeline getBundleTimeline(final SubscriptionBaseBundle bundle, final TenantContext context)
throws SubscriptionBaseRepairException {
try {
final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(bundle.getAccountId(), context);
final List<SubscriptionBase> subscriptions = dao.getSubscriptions(bundle.getId(),
ImmutableList.<SubscriptionBaseEvent>of(),
internalTenantContext);
if (subscriptions.size() == 0) {
throw new SubscriptionBaseRepairException(ErrorCode.SUB_NO_ACTIVE_SUBSCRIPTIONS, bundle.getId());
}
final String viewId = getViewId(((DefaultSubscriptionBaseBundle) bundle).getLastSysUpdateDate(), subscriptions);
final List<SubscriptionBaseTimeline> repairs = createGetSubscriptionRepairList(subscriptions, Collections.<SubscriptionBaseTimeline>emptyList(), internalTenantContext);
return createGetBundleRepair(bundle.getId(), bundle.getExternalKey(), viewId, repairs);
} catch (CatalogApiException e) {
throw new SubscriptionBaseRepairException(e);
}
}
private String getViewId(final DateTime lastUpdateBundleDate, final List<SubscriptionBase> subscriptions) {
final StringBuilder tmp = new StringBuilder();
long lastOrderedId = -1;
for (final SubscriptionBase cur : subscriptions) {
lastOrderedId = lastOrderedId < ((DefaultSubscriptionBase) cur).getLastEventOrderedId() ? ((DefaultSubscriptionBase) cur).getLastEventOrderedId() : lastOrderedId;
}
tmp.append(lastOrderedId);
tmp.append("-");
tmp.append(lastUpdateBundleDate.toDate().getTime());
return tmp.toString();
}
private BundleBaseTimeline createGetBundleRepair(final UUID bundleId, final String externalKey, final String viewId, final List<SubscriptionBaseTimeline> repairList) {
return new BundleBaseTimeline() {
@Override
public String getViewId() {
return viewId;
}
@Override
public List<SubscriptionBaseTimeline> getSubscriptions() {
return repairList;
}
@Override
public UUID getId() {
return bundleId;
}
@Override
public DateTime getCreatedDate() {
throw new UnsupportedOperationException();
}
@Override
public DateTime getUpdatedDate() {
throw new UnsupportedOperationException();
}
@Override
public String getExternalKey() {
return externalKey;
}
};
}
private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<SubscriptionBase> subscriptions, final List<SubscriptionBaseTimeline> inRepair, final InternalTenantContext tenantContext) throws CatalogApiException {
final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
final Set<UUID> repairIds = new TreeSet<UUID>();
for (final SubscriptionBaseTimeline cur : inRepair) {
repairIds.add(cur.getId());
result.add(cur);
}
for (final SubscriptionBase cur : subscriptions) {
if (!repairIds.contains(cur.getId())) {
result.add(new DefaultSubscriptionBaseTimeline((DefaultSubscriptionBase) cur, catalogService.getFullCatalog(true, true, tenantContext)));
}
}
return result;
}
}