package com.sissi.persistent.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBObject;
import com.sissi.config.Dictionary;
import com.sissi.config.MongoConfig;
import com.sissi.config.impl.MongoUtils;
import com.sissi.context.JID;
import com.sissi.context.JIDContext;
import com.sissi.persistent.Persistent;
import com.sissi.persistent.PersistentElement;
import com.sissi.pipeline.Output;
import com.sissi.protocol.Element;
/**
* 索引策略1: {"activate":1,"ack":1}</p>索引策略2: {"to":1,"activate":1,"ack":1,"class":1,"resend":1}</p>索引策略3: {"sid":1,"calss":1}</p>索引策略4: {"pid":1,"calss":1}</p>索引策略5: {"pid":1}
*
* @author kim 2013-11-15
*/
public class MongoPersistent implements Persistent, Output {
/**
* {"activate":true,"ack":false}
*/
private final DBObject[] activate = new DBObject[] { BasicDBObjectBuilder.start(Dictionary.FIELD_ACTIVATE, true).get(), BasicDBObjectBuilder.start(Dictionary.FIELD_ACK, false).get() };
/**
* 支持的XMPP节类型</p>{"in":[Xxx,Xxx]}
*/
private final DBObject support;
private final int resend;
private final MongoConfig config;
private final List<PersistentElement> elements;
/**
* @param resend 最大重发次数
* @param config
* @param elements
*/
public MongoPersistent(int resend, MongoConfig config, List<PersistentElement> elements) {
super();
this.resend = resend;
this.config = config;
this.elements = elements;
List<String> support = new ArrayList<String>();
for (PersistentElement each : elements) {
support.add(each.support().getSimpleName());
}
this.support = BasicDBObjectBuilder.start("$in", support.toArray(new String[] {})).get();
}
public boolean exists(String pid) {
return this.config.collection().findOne(BasicDBObjectBuilder.start(Dictionary.FIELD_PID, pid).get()) != null;
}
/*
* Upsert that</p>Query:{"to",jid.bare,"$or":[@see activate],"class":支持的XMPP节类型,"resend",{"$lt":Xxx}}</p>Entity:{"$set":{"activate":false,"$inc":{"resend":1}}
*
* @see com.sissi.persistent.PersistentElementBox#pull(com.sissi.context.JID)
*/
@Override
public Collection<Element> pull(JID jid) {
DBObject query = BasicDBObjectBuilder.start().add(Dictionary.FIELD_TO, jid.asStringWithBare()).add("$or", this.activate).add(Dictionary.FIELD_CLASS, this.support).add(Dictionary.FIELD_RESEND, BasicDBObjectBuilder.start("$lt", this.resend).get()).get();
Elements elements = new Elements(this.config.collection().find(query), this.elements);
// {"$set:{"activate":false,"$inc":{"resend":1}}}
this.config.collection().update(query, BasicDBObjectBuilder.start().add("$set", BasicDBObjectBuilder.start(Dictionary.FIELD_ACTIVATE, false).get()).add("$inc", BasicDBObjectBuilder.start(Dictionary.FIELD_RESEND, 1).get()).get(), false, true);
return elements;
}
/*
* Upsert that</p>Query: PersistentElement.query</p>Entity: PersistentElement.write
*
* @see com.sissi.persistent.PersistentElementBox#push(com.sissi.protocol.Element)
*/
@Override
public Persistent push(Element element) {
for (PersistentElement each : this.elements) {
if (each.isSupport(element)) {
this.config.collection().update(BasicDBObjectBuilder.start(each.query(element)).get(), BasicDBObjectBuilder.start(each.write(element)).get(), true, false);
}
}
return this;
}
public Map<String, Object> peek(Map<String, Object> query) {
return MongoUtils.asMap(this.config.collection().findOne(BasicDBObjectBuilder.start(query).get()));
}
/*
* FindAndModify
*
* @see com.sissi.persistent.PersistentElementBox#peek(java.util.Map, java.util.Map)
*/
public Map<String, Object> peek(Map<String, Object> query, Map<String, Object> update) {
return MongoUtils.asMap(this.config.collection().findAndModify(BasicDBObjectBuilder.start(query).add(Dictionary.FIELD_CLASS, this.support).get(), BasicDBObjectBuilder.start(update).get()));
}
@Override
public boolean output(JIDContext context, Element element) {
this.push(element);
return true;
}
@Override
public Output close() {
return this;
}
}