package org.societies.comm.xmpp.pubsub.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.UUID;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.societies.api.comm.xmpp.datatypes.HostedNode;
import org.societies.api.identity.IIdentity;
import org.societies.api.identity.IIdentityManager;
import org.societies.api.identity.InvalidFormatException;
import org.societies.comm.xmpp.pubsub.model.PubsubNodeDAO;
// TODO collection node support
public class PubsubNode extends HostedNode {
private static Logger LOG = LoggerFactory
.getLogger(PubsubNode.class);
private IIdentity owner;
// configurations
private Map<String, IIdentity> subscriptionsById;
private Map<IIdentity, List<String>> subscriptionsByUser;
// subscriberoptions
private Stack<String> itemIdByOrder;
private Map<String, Object> itemsById;
private Map<String, String> publisherByItemId;
// itempublishoptions??? these suck!
private SessionFactory sf;
private IIdentityManager idm;
private PubsubNodeDAO dao;
public PubsubNode(IIdentity owner, String nodeId) {
super(nodeId, null); // TODO collection nodes
this.owner = owner;
subscriptionsById = new HashMap<String, IIdentity>();
subscriptionsByUser = new HashMap<IIdentity, List<String>>();
itemIdByOrder = new Stack<String>();
itemsById = new HashMap<String, Object>();
publisherByItemId = new HashMap<String, String>();
}
public PubsubNode(PubsubNodeDAO dao, SessionFactory sf, IIdentityManager idm) {
super(dao.getNodeId(), null);
this.sf = sf;
this.idm = idm;
this.dao = dao;
subscriptionsById = new HashMap<String, IIdentity>();
subscriptionsByUser = new HashMap<IIdentity, List<String>>();
itemIdByOrder = new Stack<String>();
itemsById = new HashMap<String, Object>();
publisherByItemId = new HashMap<String, String>();
loadFromDAO();
}
public PubsubNodeDAO enablePersistence(SessionFactory sf, IIdentityManager idm) {
if (dao==null) {
this.sf = sf;
this.idm = idm;
dao = new PubsubNodeDAO();
dao.setNodeId(getNode());
dao.setOwner(owner.getBareJid());
for (String subId : subscriptionsById.keySet()) {
String subJid = subscriptionsById.get(subId).getBareJid();
dao.getSubscriptionsById().put(subId, subJid);
}
}
return dao;
}
private void loadFromDAO() {
subscriptionsById = new HashMap<String, IIdentity>();
subscriptionsByUser = new HashMap<IIdentity, List<String>>();
try {
owner = idm.fromJid(dao.getOwner());
for (String subId : dao.getSubscriptionsById().keySet()) {
String subJid = dao.getSubscriptionsById().get(subId);
// System.out.println("restoring subscription: subId="+subId+";subJid="+subJid);
IIdentity subIdentity = idm.fromJid(subJid);
subscriptionsById.put(subId, subIdentity);
List<String> subIdList = subscriptionsByUser.get(subJid);
if (subIdList==null) {
subIdList = new ArrayList<String>();
subscriptionsByUser.put(subIdentity, subIdList);
}
subIdList.add(subId);
}
} catch (InvalidFormatException e) {
LOG.error("InvalidFormatException getting identities from database", e);
}
}
private void writeToDAO(String subId) {
if (sf != null) {
Session s = sf.openSession();
Transaction tx = null;
try {
tx = s.beginTransaction();
dao = (PubsubNodeDAO) s.load(PubsubNodeDAO.class, dao.getHbnId());
if (subscriptionsById.get(subId)!=null) {
String subJid = subscriptionsById.get(subId).getBareJid();
dao.getSubscriptionsById().put(subId, subJid);
}
else {
dao.getSubscriptionsById().remove(subId);
}
s.update(dao);
tx.commit();
}
catch (HibernateException e) {
if (tx!=null)
tx.rollback();
throw e;
}
finally {
s.close();
}
}
}
public PubsubNodeDAO getDAO() {
return dao;
}
public String newSubscription(IIdentity subscriber) {
// Generate subId
String subId = UUID.randomUUID().toString();
while (subscriptionsById.containsKey(subId))
subId = UUID.randomUUID().toString();
// Subscribe
subscriptionsById.put(subId, subscriber);
List<String> subIdList = subscriptionsByUser.get(subscriber);
if (subIdList==null) {
subIdList = new ArrayList<String>();
subscriptionsByUser.put(subscriber, subIdList);
}
subIdList.add(subId);
writeToDAO(subId);
return subId;
}
public List<String> getSubscriptions(IIdentity subscriber) {
return subscriptionsByUser.get(subscriber);
}
public Collection<IIdentity> getSubscribers() {
//return subscriptionsByUser.keySet();
return subscriptionsById.values();
}
public void unsubscribe(String string) {
IIdentity subscriber = subscriptionsById.get(string);
subscriptionsById.remove(string);
subscriptionsByUser.remove(subscriber); // removes all subscriptions... TODO handle subIds separately
writeToDAO(string);
}
public String publishItem(String itemId, Object itemObject, String publisher) {
if (itemId!=null) {
// Check for existing itemId and delete old item
Object oldItem = itemsById.get(itemId);
if (oldItem!=null) {
itemsById.remove(itemId);
itemIdByOrder.remove(itemId); // TODO pop the changed item to the top of the stack?
}
}
else {
// Generate itemId
itemId = UUID.randomUUID().toString();
while (itemsById.containsKey(itemId))
itemId = UUID.randomUUID().toString();
}
// Publish
itemsById.put(itemId, itemObject);
itemIdByOrder.push(itemId);
publisherByItemId.put(itemId, publisher);
return itemId;
}
public Object getItemPayload(String itemId) {
return itemsById.get(itemId);
}
public List<String> getItemIds() {
return Collections.unmodifiableList(itemIdByOrder);
}
public void removeItem(String itemId) {
itemsById.remove(itemId);
itemIdByOrder.remove(itemId);
}
public void purge() {
itemIdByOrder = new Stack<String>();
itemsById = new HashMap<String, Object>();
publisherByItemId = new HashMap<String, String>();
}
public IIdentity getOwner() {
return owner;
}
}