package org.mobicents.slee.sipevent.server.subscription.eventlist;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import org.apache.log4j.Logger;
import org.mobicents.slee.sipevent.server.subscription.eventlist.rlmi.Instance;
import org.mobicents.slee.sipevent.server.subscription.eventlist.rlmi.List;
import org.mobicents.slee.sipevent.server.subscription.eventlist.rlmi.Name;
import org.mobicents.slee.sipevent.server.subscription.eventlist.rlmi.Resource;
import org.openxdm.xcap.client.appusage.resourcelists.jaxb.EntryType;
import org.openxdm.xcap.client.appusage.resourcelists.jaxb.EntryType.DisplayName;
public class NotificationData implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/*
* JAXB context is thread safe
*/
protected static final JAXBContext rlmiJaxbContext = initJAXBContext();
private static final Logger logger = Logger.getLogger(NotificationData.class);
private static JAXBContext initJAXBContext() {
try {
return JAXBContext
.newInstance("org.mobicents.slee.sipevent.server.subscription.eventlist.rlmi");
} catch (JAXBException e) {
logger.error("failed to create jaxb context");
return null;
}
}
private final HashSet<String> urisLeft = new HashSet<String>();
private final ArrayList<EntryType> entries = new ArrayList<EntryType>();
private final int version;
private final String notifier;
private final HashMap<String,BodyPart> bodyParts = new HashMap<String, BodyPart>();
private final HashMap<String,Instance> instances = new HashMap<String, Instance>();
private final boolean fullState;
private final String rlmiCid;
private final String multiPartBoundary;
private AtomicBoolean locked = new AtomicBoolean(false);
public NotificationData(String notifier, int version, FlatList flatList, String rlmiCid, String multiPartBoundary) {
this.version = version;
this.notifier = notifier;
this.fullState = true;
this.rlmiCid = rlmiCid;
this.multiPartBoundary = multiPartBoundary;
for (EntryType entryType : flatList.getEntries().values()) {
urisLeft.add(entryType.getUri());
entries.add(entryType);
}
}
public NotificationData(String notifier, int version, EntryType entryType, String rlmiCid, String multiPartBoundary) {
this.version = version;
this.notifier = notifier;
this.fullState = false;
this.rlmiCid = rlmiCid;
this.multiPartBoundary = multiPartBoundary;
urisLeft.add(entryType.getUri());
entries.add(entryType);
}
/**
* Adds notification data for a resource
* @return if all required data is added a {@link MultiPart} will be returned, otherwise null
*/
public MultiPart addNotificationData(String uri, String cid, String instanceId, String content, String contentType, String contentSubType, String status, String reason) throws IllegalStateException {
if (cid != null) {
bodyParts.put(uri, new BodyPart("binary",cid,contentType,contentSubType,"UTF-8",content));
}
Instance instance = new Instance();
instance.setId(instanceId);
instance.setCid(cid);
instance.setState(status);
instance.setReason(reason);
instances.put(uri, instance);
return notificationDataNotNeeded(uri);
}
/**
* Indicates no notification data for a resource, possibly due to an error, from this invocation this resource won't count on the verification for complete notification data & multipart building
* @return if all required data is added a {@link MultiPart} will be returned, otherwise null
*/
public MultiPart notificationDataNotNeeded(String uri) throws IllegalStateException {
urisLeft.remove(uri);
if (urisLeft.isEmpty()) {
return buildMultipart();
}
else {
return null;
}
}
private MultiPart buildMultipart() throws IllegalStateException {
// check lock
if (!locked.compareAndSet(false, true)) {
throw new IllegalStateException();
}
// create rlmi
List rlmiList = new List();
rlmiList.setFullState(fullState);
rlmiList.setVersion(version);
rlmiList.setUri(notifier);
for (EntryType entryType : entries) {
Resource resource = new Resource();
resource.setUri(entryType.getUri());
DisplayName displayName = entryType.getDisplayName();
if (displayName != null) {
Name name = new Name();
name.setLang(displayName.getLang());
name.setValue(displayName.getValue());
resource.getName().add(name);
}
Instance instance = instances.get(entryType.getUri());
if (instance != null) {
resource.getInstance().add(instance);
}
rlmiList.getResource().add(resource);
}
// marshall it
String rlmiString = marshallRlmi(rlmiList);
// create multipart
MultiPart multiPart = new MultiPart(multiPartBoundary,"application/rlmi+xml");
// add rlmi body part
multiPart.getBodyParts().add(new BodyPart("binary",rlmiCid,"application","rlmi+xml","UTF-8",rlmiString));
// add remaining body parts
for (BodyPart bodyPart : bodyParts.values()) {
multiPart.getBodyParts().add(bodyPart);
}
return multiPart;
}
private String marshallRlmi(List rlmiList) {
StringWriter stringWriter = new StringWriter();
String result = null;
try {
rlmiJaxbContext.createMarshaller().marshal(rlmiList, stringWriter);
result = stringWriter.toString();
}
catch (Exception e) {
logger.error("failed to marshall rlmi content",e);
}
try {
stringWriter.close();
} catch (Exception e) {
logger.error("failed to close stringwriter used to marshall rlmi content",e);
}
return result;
}
@Override
public int hashCode() {
return notifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass() == this.getClass()) {
return ((NotificationData)obj).notifier.equals(this.notifier);
}
else {
return false;
}
}
}