/*
* Tigase Jabber/XMPP Server
* Copyright (C) 2004-2012 "Artur Hefczyc" <artur.hefczyc@tigase.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. Look for COPYING file in the top folder.
* If not, see http://www.gnu.org/licenses/.
*
* $Rev$
* Last modified by $Author$
* $Date$
*/
package tigase.server.sreceiver;
//~--- non-JDK imports --------------------------------------------------------
import tigase.server.Message;
import tigase.server.Packet;
import tigase.sys.TigaseRuntime;
import tigase.util.TigaseStringprepException;
import tigase.xml.Element;
import tigase.xmpp.JID;
import tigase.xmpp.StanzaType;
import static tigase.server.sreceiver.PropertyConstants.*;
//~--- JDK imports ------------------------------------------------------------
import java.util.Date;
import java.util.Map;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
//~--- classes ----------------------------------------------------------------
/**
* Created: Jan 22, 2009 11:02:59 AM
*
* @author <a href="mailto:artur.hefczyc@tigase.org">Artur Hefczyc</a>
* @version $Rev$
*/
public class PubSubTestsTask extends RepoRosterTask {
private enum command {
help(" - Displays help info."), newnodes(" N - Create N nodes in the pubsub."),
newsubscr(" node-name N - create N subscriptions for a given node name."),
newnodessubscr(" N M - create N nodes with M subscriptions each."),
setdelay(" N - set the delay between sending node creation packet."),
stop(" - Stops the current packets generation.");
private String helpText = null;
//~--- constructors -------------------------------------------------------
private command(String helpText) {
this.helpText = helpText;
}
//~--- get methods --------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public String getHelp() {
return helpText;
}
}
//~--- static fields --------------------------------------------------------
private static final String TASK_TYPE = "PubSub tests";
private static final String TASK_HELP =
"This is a PubSub component testing task."
+ " Only for testing and only to be run by an admnistrator.";
//~--- fields ---------------------------------------------------------------
private long delay = 2000;
private Element conf = new Element("x",
new Element[] { new Element("field",
new Element[] { new Element("value",
"http://jabber.org/protocol/pubsub#node_config") },
new String[] { "var", "type" },
new String[] { "FORM_TYPE", "hidden" }), new Element("field",
new Element[] { new Element("value",
"0") },
new String[] { "var" },
new String[] { "pubsub#notify_sub_aff_state" }) },
new String[] { "xmlns", "type" },
new String[] { "jabber:x:data", "submit" });
private String[] last_nodes = null;
private long packetsGenerated = 0;
private boolean stop = false;
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
@Override
public Map<String, PropertyItem> getDefaultParams() {
Map<String, PropertyItem> defs = super.getDefaultParams();
defs.put(DESCRIPTION_PROP_KEY,
new PropertyItem(DESCRIPTION_PROP_KEY,
DESCRIPTION_DISPL_NAME,
"PubSub Testing Task"));
defs.put(MESSAGE_TYPE_PROP_KEY,
new PropertyItem(MESSAGE_TYPE_PROP_KEY,
MESSAGE_TYPE_DISPL_NAME,
MessageType.NORMAL));
defs.put(ONLINE_ONLY_PROP_KEY,
new PropertyItem(ONLINE_ONLY_PROP_KEY, ONLINE_ONLY_DISPL_NAME, false));
defs.put(REPLACE_SENDER_PROP_KEY,
new PropertyItem(REPLACE_SENDER_PROP_KEY,
REPLACE_SENDER_DISPL_NAME,
SenderAddress.LEAVE));
defs.put(SUBSCR_RESTRICTIONS_PROP_KEY,
new PropertyItem(SUBSCR_RESTRICTIONS_PROP_KEY,
SUBSCR_RESTRICTIONS_DISPL_NAME,
SubscrRestrictions.MODERATED));
return defs;
}
/**
* Method description
*
*
* @return
*/
@Override
public String getHelp() {
return TASK_HELP;
}
/**
* Method description
*
*
* @return
*/
@Override
public String getType() {
return TASK_TYPE;
}
//~--- methods --------------------------------------------------------------
@Override
protected boolean addOutPacket(Packet packet) {
++packetsGenerated;
return super.addOutPacket(packet);
}
@Override
protected void processMessage(Packet packet, Queue<Packet> results) {
if (isPostCommand(packet)) {
runCommand(packet, results);
}
}
private void addSubscriptionsForNode(JID from, JID to, String node, int subscr) {
int j = 0;
Element el = createPubSubEl(from,
to,
"ids-" + (++j),
node,
"subscriptions",
"http://jabber.org/protocol/pubsub#owner");
for (int i = 0; i < subscr; i++) {
Element subs = new Element("subscription",
new String[] { "jid", "subscription" },
new String[] { "frank-" + i + "@" + getJID().getDomain(),
"subscribed" });
el.findChild("/iq/pubsub/subscriptions").addChild(subs);
if (i % 100 == 0) {
addOutPacket(Packet.packetInstance(el, from, to));
el = createPubSubEl(from, to, "ids-" + (++j), node, "subscriptions",
"http://jabber.org/protocol/pubsub#owner");
}
}
addOutPacket(Packet.packetInstance(el, from, to));
}
private void addSubscriptionsForNodes(JID from, JID to, String[] nodes, int subscr) {
for (String node : nodes) {
addSubscriptionsForNode(from, to, node, subscr);
}
}
private String commandsHelp() {
StringBuilder sb = new StringBuilder();
for (command comm : command.values()) {
sb.append("//" + comm.name() + comm.getHelp() + "\n");
}
return "Available commands are:\n" + sb.toString();
}
private String[] createNodes(JID from, JID to, int... nums) {
String[] nodes = new String[nums[0]];
for (int i = 0; i < nums[0]; i++) {
if (stop) {
break;
}
String node = "node-" + i;
nodes[i] = node;
Element el = createPubSubEl(from,
to,
"id-" + i,
node,
"create",
"http://jabber.org/protocol/pubsub");
el.findChild("/iq/pubsub").addChild(new Element("configure"));
el.findChild("/iq/pubsub/configure").addChild(conf);
addOutPacket(Packet.packetInstance(el, from, to));
if ((nums.length > 1) && (nums[1] > 0)) {
addSubscriptionsForNode(from, to, node, nums[1]);
}
while (memoryLow()) {
try {
System.gc();
Thread.sleep(delay);
} catch (Exception e) {}
}
}
stop = false;
// if (nums.length > 1 && nums[1] > 0) {
// addSubscriptionsForNodes(from, nodes, nums[1]);
// }
return nodes;
}
private Element createPubSubEl(JID from, JID to, String id, String node, String pubsub_call,
String xmlns) {
Element elem = new Element("iq",
new Element[] { new Element("pubsub",
new Element[] { new Element(pubsub_call,
new String[] { "node" },
new String[] { node }) },
new String[] { "xmlns" },
new String[] { xmlns }) },
new String[] { "type", "from", "to", "id" },
new String[] { "set", from.toString(), to.toString(), id });
return elem;
}
//~--- get methods ----------------------------------------------------------
private boolean isPostCommand(Packet packet) {
String body = packet.getElemCData("/message/body");
if (body != null) {
for (command comm : command.values()) {
if (body.startsWith("//" + comm.toString())) {
return true;
}
}
}
return false;
}
//~--- methods --------------------------------------------------------------
private boolean memoryLow() {
return TigaseRuntime.getTigaseRuntime().getHeapMemUsage() > 80f;
}
;
//~--- methods --------------------------------------------------------------
private int[] parseNumbers(String[] args, int pos, int num) {
// The first arg is command name, after that command parameters come
int[] res = new int[num];
for (int i = 0; i < res.length; i++) {
try {
res[i] = Integer.parseInt(args[i + pos]);
} catch (Exception e) {
return null;
}
}
return res;
}
private void runCommand(final Packet packet, Queue<Packet> results) {
String body = packet.getElemCData("/message/body");
final String[] body_split = body.split("\\s");
command comm = command.valueOf(body_split[0].substring(2));
final int[] pars;
final JID to = JID.jidInstanceNS("pubsub." + getJID().getDomain());
switch (comm) {
case help :
results.offer(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat, commandsHelp(),
"Commands description", null, packet.getStanzaId()));
break;
case setdelay :
pars = parseNumbers(body_split, 1, 1);
if (pars != null) {
delay = pars[0];
}
break;
case newnodes :
pars = parseNumbers(body_split, 1, 1);
if (pars != null) {
addOutPacket(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat, "Task accepted, processing...",
"PubSub testing task", null, packet.getStanzaId()));
runInThread(new Runnable() {
@Override
public void run() {
last_nodes = createNodes(packet.getStanzaFrom(), to, pars);
}
}, packet);
} else {
results.offer(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat, "Incorrect command parameters.",
"PubSub testing task", null, packet.getStanzaId()));
return;
}
break;
case newsubscr :
if (last_nodes != null) {
pars = parseNumbers(body_split, 2, 1);
if (pars != null) {
addOutPacket(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat, "Task accepted, processing...",
"PubSub testing task", null,
packet.getStanzaId()));
runInThread(new Runnable() {
@Override
public void run() {
addSubscriptionsForNode(packet.getStanzaFrom(), to, body_split[1], pars[0]);
}
}, packet);
} else {
results.offer(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat, "Incorrect command parameters.",
"PubSub testing task", null,
packet.getStanzaId()));
return;
}
} else {
results.offer(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat,
"There are no pubsub nodes created yet.",
"PubSub testing task", null, packet.getStanzaId()));
return;
}
break;
case newnodessubscr :
pars = parseNumbers(body_split, 1, 2);
if (pars != null) {
addOutPacket(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat,
"" + new Date() + " Task accepted, processing...",
"PubSub testing task", null, packet.getStanzaId()));
runInThread(new Runnable() {
@Override
public void run() {
last_nodes = createNodes(packet.getStanzaFrom(), to, pars);
}
}, packet);
} else {
results.offer(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat, "Incorrect command parameters.",
"PubSub testing task", null, packet.getStanzaId()));
return;
}
break;
case stop :
stop = true;
break;
}
}
private void runInThread(final Runnable job, final Packet packet) {
Thread thr = new Thread() {
@Override
public void run() {
long gen_start = System.currentTimeMillis();
job.run();
long gen_end = System.currentTimeMillis();
long gen_time = gen_end - gen_start;
long gen_hours = gen_time / 3600000;
long gen_mins = (gen_time - (gen_hours * 3600000)) / 60000;
long gen_secs = (gen_time - ((gen_hours * 3600000) + (gen_mins * 60000))) / 1000;
addOutPacket(Message.getMessage(packet.getStanzaTo(), packet.getStanzaFrom(),
StanzaType.chat,
"" + new Date()
+ " Generation of the test data completed.\n"
+ "Generated in: " + gen_hours + "h, " + gen_mins
+ "m, " + gen_secs + "sec" + ", packets generated: "
+ packetsGenerated, "PubSub testing task", null,
packet.getStanzaId()));
}
};
thr.setName("pubsub-test-job");
thr.start();
}
}
//~ Formatted in Sun Code Convention
//~ Formatted by Jindent --- http://www.jindent.com