package org.openstack.atlas.atomhopper.factory;
import com.rackspace.docs.core.event.DC;
import com.rackspace.docs.core.event.EventType;
import com.rackspace.docs.core.event.Region;
import com.rackspace.docs.core.event.V1Element;
import com.rackspace.docs.usage.lbaas.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openstack.atlas.atomhopper.exception.AtomHopperMappingException;
import org.openstack.atlas.atomhopper.marshaller.UsageMarshaller;
import org.openstack.atlas.atomhopper.util.AHUSLServiceUtil;
import org.openstack.atlas.atomhopper.util.UUIDUtil;
import org.openstack.atlas.cfg.Configuration;
import org.openstack.atlas.restclients.atomhopper.config.AtomHopperConfiguration;
import org.openstack.atlas.restclients.atomhopper.config.AtomHopperConfigurationKeys;
import org.openstack.atlas.service.domain.entities.Usage;
import org.openstack.atlas.service.domain.events.UsageEvent;
import org.openstack.atlas.service.domain.events.entities.SslMode;
import org.openstack.atlas.service.domain.usage.BitTag;
import org.openstack.atlas.service.domain.usage.BitTags;
import org.w3._2005.atom.*;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeConfigurationException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Used for mapping values from usage records to generate usage objects...
*/
public class UsageEntryFactoryImpl implements UsageEntryFactory {
private static final Log LOG = LogFactory.getLog(UsageEntryFactoryImpl.class);
private static final String USAGE_LABEL = "loadBalancerUsage";
private static final String LBAAS_TITLE = "cloudLoadBalancers";
private static final String SERVICE_CODE = "CloudLoadBalancers";
private static final String USAGE_VERSION = "1";
protected Configuration atomHopperConfig;
private org.w3._2005.atom.ObjectFactory usageEntryFactory;
private com.rackspace.docs.usage.lbaas.ObjectFactory lbUsageFactory;
private com.rackspace.docs.event.lbaas.delete.ObjectFactory lbDeleteFactory;
private com.rackspace.docs.core.event.ObjectFactory v1EventFactory;
public UsageEntryFactoryImpl() {
this.atomHopperConfig = new AtomHopperConfiguration();
this.usageEntryFactory = new org.w3._2005.atom.ObjectFactory();
this.lbUsageFactory = new com.rackspace.docs.usage.lbaas.ObjectFactory();
this.lbDeleteFactory = new com.rackspace.docs.event.lbaas.delete.ObjectFactory();
this.v1EventFactory = new com.rackspace.docs.core.event.ObjectFactory();
}
@Override
public Map<Object, Object> createEntry(Usage usageRecord) throws AtomHopperMappingException {
try {
UsageEntry entry = buildEntry();
entry.getCategory().add(buildUsageCategory());
entry.setContent(generateUsageContent(generateV1Event(usageRecord), MediaType.APPLICATION_XML));
return generateUsageEntryMap(entry);
} catch (Exception e) {
LOG.error("Error mapping usage: " + e);
throw new AtomHopperMappingException(e);
}
}
private V1Element generateV1Event(Usage usageRecord) throws DatatypeConfigurationException, NoSuchAlgorithmException, JAXBException {
V1Element usageV1 = generateBaseUsageEvent(usageRecord);
usageV1.setId(genUUIDObject(usageRecord).toString());
if (usageRecord.getUuid() != null && usageRecord.isCorrected()) {
//This is an updated usage record, need the reference id from previous record
usageV1.setReferenceId(usageRecord.getUuid());
}
usageV1.setTenantId(usageRecord.getAccountId().toString());
usageV1.setResourceId(usageRecord.getLoadbalancer().getId().toString());
usageV1.setResourceName(usageRecord.getLoadbalancer().getName());
EventType usageRecordEventType = mapEventType(usageRecord);
if (usageRecordEventType != null && (usageRecordEventType.equals(EventType.DELETE))) {
usageV1.setEventTime(AHUSLServiceUtil.processCalendar(usageRecord.getStartTime()));
usageV1.setType(EventType.DELETE);
usageV1.getAny().add(lbDeleteFactory.createProduct(buildLbaasUsageRecordDelete()));
} else {
usageV1.setType(EventType.USAGE);
usageV1.setStartTime(AHUSLServiceUtil.processCalendar(usageRecord.getStartTime()));
usageV1.setEndTime(AHUSLServiceUtil.processCalendar(usageRecord.getEndTime()));
usageV1.getAny().add(lbUsageFactory.createProduct(buildLbaasUsageRecord(usageRecord)));
}
return usageV1;
}
private V1Element generateBaseUsageEvent(Usage usageRecord) throws DatatypeConfigurationException {
V1Element baseEvent = v1EventFactory.createV1Element();
baseEvent.setVersion(USAGE_VERSION);
baseEvent.setRegion(mapRegion(atomHopperConfig.getString(AtomHopperConfigurationKeys.ahusl_region)));
baseEvent.setDataCenter(DC.fromValue(atomHopperConfig.getString(AtomHopperConfigurationKeys.ahusl_data_center)));
return baseEvent;
}
private CloudLoadBalancersType buildLbaasUsageRecord(Usage usageRecord) throws DatatypeConfigurationException {
CloudLoadBalancersType lbaasUsage = lbUsageFactory.createCloudLoadBalancersType();
lbaasUsage.setAvgConcurrentConnections(usageRecord.getAverageConcurrentConnections());
lbaasUsage.setAvgConcurrentConnectionsSsl(usageRecord.getAverageConcurrentConnectionsSsl());
lbaasUsage.setBandWidthOutSsl(usageRecord.getOutgoingTransferSsl());
lbaasUsage.setBandWidthInSsl(usageRecord.getIncomingTransferSsl());
lbaasUsage.setBandWidthOut(usageRecord.getOutgoingTransfer());
lbaasUsage.setBandWidthIn(usageRecord.getIncomingTransfer());
lbaasUsage.setResourceType(ResourceTypes.LOADBALANCER);
lbaasUsage.setNumPolls(usageRecord.getNumberOfPolls());
lbaasUsage.setNumVips(usageRecord.getNumVips());
lbaasUsage.setServiceCode(SERVICE_CODE);
lbaasUsage.setVersion(USAGE_VERSION);
StatusEnum status = (mapEventType(usageRecord) != null
&& mapEventType(usageRecord).equals(EventType.SUSPEND))
? StatusEnum.SUSPENDED : StatusEnum.ACTIVE;
lbaasUsage.setStatus(status);
BitTags bitTags = new BitTags(usageRecord.getTags());
if (bitTags.isTagOn(BitTag.SERVICENET_LB)) {
lbaasUsage.setVipType(VipTypeEnum.SERVICENET);
} else {
lbaasUsage.setVipType(VipTypeEnum.PUBLIC);
}
lbaasUsage.setSslMode(SslModeEnum.fromValue(SslMode.getMode(bitTags).name()));
return lbaasUsage;
}
private com.rackspace.docs.event.lbaas.delete.CloudLoadBalancersType buildLbaasUsageRecordDelete() throws DatatypeConfigurationException {
com.rackspace.docs.event.lbaas.delete.CloudLoadBalancersType lbaasUsage = lbDeleteFactory.createCloudLoadBalancersType();
lbaasUsage.setResourceType(com.rackspace.docs.event.lbaas.delete.ResourceTypes.LOADBALANCER);
lbaasUsage.setServiceCode(SERVICE_CODE);
lbaasUsage.setVersion(USAGE_VERSION);
return lbaasUsage;
}
private UsageContent generateUsageContent(V1Element v1Element, String contentType) {
UsageContent content = usageEntryFactory.createUsageContent();
content.setEvent(v1Element);
content.setType(contentType);
return content;
}
private String genUUIDString(Usage usageRecord) {
return SERVICE_CODE
+ "_" + usageRecord.getLoadbalancer().getId()
+ "_" + usageRecord.getStartTime()
+ "_" + usageRecord.getEndTime()
+ "_" + atomHopperConfig.getString(AtomHopperConfigurationKeys.ahusl_region)
+ "_" + usageRecord.getEntryVersion();
}
private UsageEntry buildEntry() {
UsageEntry entry = usageEntryFactory.createUsageEntry();
Title title = new Title();
title.setType(Type.TEXT);
title.setValue(LBAAS_TITLE);
entry.setTitle(title);
return entry;
}
private UUID genUUIDObject(Usage usageRecord) throws NoSuchAlgorithmException {
return UUIDUtil.genUUIDMD5Hash(genUUIDString(usageRecord));
}
private UsageCategory buildUsageCategory() {
UsageCategory usageCategory = usageEntryFactory.createUsageCategory();
usageCategory.setLabel(USAGE_LABEL);
usageCategory.setTerm("plain");
return usageCategory;
}
private Map<Object, Object> generateUsageEntryMap(UsageEntry usageEntry) throws JAXBException {
Map<Object, Object> map = new HashMap<Object, Object>();
JAXBContext context;
if (usageEntry.getContent().getEvent().getType().equals(EventType.DELETE)) {
context = JAXBContext.newInstance("org.w3._2005.atom:com.rackspace.docs.event.lbaas.delete");
} else {
context = JAXBContext.newInstance("org.w3._2005.atom:com.rackspace.docs.usage.lbaas");
}
map.put("entrystring", UsageMarshaller
.marshallResource(usageEntryFactory.createEntry(usageEntry), context).toString());
map.put("entryobject", usageEntry);
return map;
}
/**
* This method maps string events to EventType
*
* @param usageRecord
* @return
* @throws javax.xml.datatype.DatatypeConfigurationException
*/
public static EventType mapEventType(Usage usageRecord) throws DatatypeConfigurationException {
if (usageRecord.getEventType() != null) {
if (usageRecord.getEventType().equals(UsageEvent.CREATE_LOADBALANCER.name())) {
return EventType.CREATE;
} else if (usageRecord.getEventType().equals(UsageEvent.DELETE_LOADBALANCER.name())) {
return EventType.DELETE;
} else if (usageRecord.getEventType().equals(UsageEvent.SUSPEND_LOADBALANCER.name())) {
return EventType.SUSPEND;
} else if (usageRecord.getEventType().equals(UsageEvent.SUSPENDED_LOADBALANCER.name())) {
return EventType.SUSPEND;
} else if (usageRecord.getEventType().equals(UsageEvent.UNSUSPEND_LOADBALANCER.name())) {
return EventType.UNSUSPEND;
}
}
return null;
}
public static Region mapRegion(String configRegion) {
if (configRegion.equals("DFW")) {
return Region.DFW;
} else if (configRegion.equals("ORD")) {
return Region.ORD;
} else if (configRegion.equals("LON")) {
return Region.LON;
} else if (configRegion.equals("SYD")) {
return Region.SYD;
} else if (configRegion.equals("IAD")) {
return Region.IAD;
} else if (configRegion.equals("HKG")) {
return Region.HKG;
} else {
LOG.error("Region could not be mapped from config, using default");
return Region.GLOBAL;
}
}
}