You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by be...@apache.org on 2010/12/28 13:35:11 UTC
svn commit: r1053331 - in
/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp:
modules/extension/xep0050_adhoc_commands/
modules/extension/xep0133_service_administration/
modules/extension/xep0133_service_administration/command/ protocol/
Author: berndf
Date: Tue Dec 28 12:35:11 2010
New Revision: 1053331
URL: http://svn.apache.org/viewvc?rev=1053331&view=rev
Log:
VYSPER-169, VYSPER-170: initial implementation of command infrastructure. 2 service commands: add user, get no. of online users
Added:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AbstractAdhocCommandHandler.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandHandler.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandIQHandler.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandSupport.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsModule.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsService.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/CommandInfo.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/Note.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/ServiceAdministrationModule.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/AddUserCommandHandler.java
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/GetOnlineUsersCommandHandler.java
Modified:
mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AbstractAdhocCommandHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AbstractAdhocCommandHandler.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AbstractAdhocCommandHandler.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AbstractAdhocCommandHandler.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,57 @@
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.stanza.dataforms.DataForm;
+import org.apache.vysper.xmpp.stanza.dataforms.DataFormEncoder;
+import org.apache.vysper.xmpp.stanza.dataforms.Field;
+import org.apache.vysper.xmpp.uuid.JVMBuiltinUUIDGenerator;
+import org.apache.vysper.xmpp.uuid.UUIDGenerator;
+
+/**
+ */
+public abstract class AbstractAdhocCommandHandler implements AdhocCommandHandler {
+
+ private static UUIDGenerator SESSION_ID_GENERATOR = new JVMBuiltinUUIDGenerator();
+ protected static final DataFormEncoder DATA_FORM_ENCODER = new DataFormEncoder();
+
+ protected boolean isExecuting = true;
+ protected boolean isPrevAllowed = false;
+ protected boolean isNextAllowed = false;
+ protected String sessionId = SESSION_ID_GENERATOR.create();
+
+ public boolean isExecuting() {
+ return isExecuting;
+ }
+
+ public String getSessionId() {
+ return sessionId;
+ }
+
+ public boolean isPrevAllowed() {
+ return isPrevAllowed;
+ }
+
+ public boolean isNextAllowed() {
+ return isNextAllowed;
+ }
+
+ protected void addFormTypeField(DataForm dataForm) {
+ dataForm.addField(new Field("", Field.Type.HIDDEN, Field.FORM_TYPE, NamespaceURIs.XEP0133_SERVICE_ADMIN));
+ }
+
+ protected DataForm createFormForm(final String title, final String instruction) {
+ final DataForm dataForm = new DataForm();
+ dataForm.setTitle(title);
+ dataForm.addInstruction(instruction);
+ dataForm.setType(DataForm.Type.form);
+ addFormTypeField(dataForm);
+ return dataForm;
+ }
+
+ protected DataForm createResultForm() {
+ final DataForm dataForm = new DataForm();
+ dataForm.setType(DataForm.Type.result);
+ addFormTypeField(dataForm);
+ return dataForm;
+ }
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandHandler.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandHandler.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandHandler.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+import org.apache.vysper.xml.fragment.XMLElement;
+
+import java.util.List;
+
+/**
+ * handles execution of a single specific command
+ */
+public interface AdhocCommandHandler {
+
+ boolean isExecuting();
+
+ String getSessionId();
+
+ XMLElement process(List<XMLElement> commandElements, List<Note> notes);
+
+ boolean isPrevAllowed();
+
+ boolean isNextAllowed();
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandIQHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandIQHandler.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandIQHandler.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandIQHandler.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,204 @@
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.vysper.xml.fragment.XMLElement;
+import org.apache.vysper.xml.fragment.XMLSemanticError;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.modules.core.base.handler.DefaultIQHandler;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.server.response.ServerErrorResponses;
+import org.apache.vysper.xmpp.stanza.IQStanza;
+import org.apache.vysper.xmpp.stanza.IQStanzaType;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.apache.vysper.xmpp.stanza.StanzaBuilder;
+import org.apache.vysper.xmpp.stanza.StanzaErrorCondition;
+import org.apache.vysper.xmpp.stanza.StanzaErrorType;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ */
+public class AdhocCommandIQHandler extends DefaultIQHandler {
+
+ protected final Collection<AdhocCommandSupport> adhocCommandSupporters;
+ protected final Map<String, AdhocCommandHandler> runningCommands = new HashMap<String, AdhocCommandHandler>();
+
+ public AdhocCommandIQHandler(Collection<AdhocCommandSupport> adhocCommandSupporters) {
+ this.adhocCommandSupporters = adhocCommandSupporters;
+ }
+
+ @Override
+ protected boolean verifyNamespace(Stanza stanza) {
+ return verifyInnerNamespace(stanza, NamespaceURIs.XEP0050_ADHOC_COMMANDS);
+ }
+
+ @Override
+ protected boolean verifyInnerElement(Stanza stanza) {
+ return verifyInnerElementWorker(stanza, "command");
+ }
+
+ @Override
+ protected Stanza handleSet(IQStanza stanza, ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext) {
+ Entity from = stanza.getFrom();
+ if (from == null) {
+ from = sessionContext.getInitiatingEntity();
+ }
+
+ AdhocCommandHandler commandHandler = null;
+ String commandNode;
+ String requestedSessionId;
+ String action; // execute | cancel
+ List<XMLElement> commandElements = null;
+ try {
+ XMLElement commandElement = stanza.getSingleInnerElementsNamed("command");
+ if (commandElement == null) {
+ return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.BAD_REQUEST, stanza,
+ StanzaErrorType.MODIFY, "command is missing", null, null);
+ }
+ commandNode = commandElement.getAttributeValue("node");
+ requestedSessionId = commandElement.getAttributeValue("sessionid");
+ action = commandElement.getAttributeValue("action");
+
+ if (StringUtils.isEmpty(requestedSessionId)) {
+ for (AdhocCommandSupport commandSupport : adhocCommandSupporters) {
+ commandHandler = commandSupport.getCommandHandler(commandNode, from);
+ if (commandHandler != null) {
+ runningCommands.put(commandHandler.getSessionId(), commandHandler);
+ break;
+ }
+ }
+ } else {
+ commandHandler = runningCommands.get(requestedSessionId);
+ if (commandHandler == null) {
+ return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.BAD_REQUEST, stanza,
+ StanzaErrorType.CANCEL, "command session id not found: " + requestedSessionId, null, null);
+ }
+ }
+ commandElements = commandElement.getInnerElements();
+ } catch (XMLSemanticError xmlSemanticError) {
+ return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.BAD_REQUEST, stanza,
+ StanzaErrorType.MODIFY, "command is not well-formed", null, null);
+ }
+
+ if ("cancel".equals(action)) {
+ runningCommands.remove(requestedSessionId);
+ return buildResponse(stanza, from, commandNode, requestedSessionId, "canceled");
+ }
+
+ // handle unauthorized access (or command does not exist at all)
+ if (commandHandler == null) {
+ return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.FORBIDDEN, stanza,
+ StanzaErrorType.CANCEL, "command is not available", null, null);
+ }
+
+ List<Note> notes = new ArrayList<Note>();
+ final XMLElement result = commandHandler.process(commandElements, notes);
+
+ final String sessionId = commandHandler.getSessionId();
+ final boolean isExecuting = commandHandler.isExecuting();
+
+ final Stanza response = buildResponse(stanza, from, commandNode, sessionId,
+ isExecuting ? "executing" : "completed", result, notes,
+ commandHandler.isPrevAllowed(), commandHandler.isNextAllowed());
+ return response;
+ }
+
+ private Stanza buildResponse(IQStanza stanza, Entity from, String commandNode, String sessionId,
+ final String status) {
+ return buildResponse(stanza, from, commandNode, sessionId, status, null, null, false, false);
+ }
+
+ private Stanza buildResponse(IQStanza stanza, Entity from, String commandNode, String sessionId,
+ final String status, XMLElement result,
+ List<Note> notes, boolean isPrevAllowed, boolean isNextAllowed) {
+ final StanzaBuilder iqStanza = StanzaBuilder.createIQStanza(null, from, IQStanzaType.RESULT, stanza.getID());
+ iqStanza.startInnerElement("command");
+ iqStanza.declareNamespace("", NamespaceURIs.XEP0050_ADHOC_COMMANDS);
+ iqStanza.addAttribute("node", commandNode);
+ iqStanza.addAttribute("sessionid", sessionId);
+ iqStanza.addAttribute("status", status);
+ if (notes != null && notes.size() > 0) {
+ for (Note note : notes) {
+ iqStanza.startInnerElement("note");
+ iqStanza.addAttribute("type", note.getType().name());
+ if (note.getText() != null) iqStanza.addText(note.getText());
+ iqStanza.endInnerElement();
+ }
+ }
+ if (isNextAllowed || isPrevAllowed) {
+ iqStanza.startInnerElement("action");
+ if (isPrevAllowed) iqStanza.startInnerElement("prev").endInnerElement();
+ if (isNextAllowed) iqStanza.startInnerElement("next").endInnerElement();
+ iqStanza.endInnerElement();
+ }
+ if (result != null) {
+ iqStanza.addPreparedElement(result);
+ }
+ iqStanza.endInnerElement();
+
+ return iqStanza.build();
+ }
+/*
+<iq from='shakespeare.lit'
+ id='add-user-1'
+ to='bard@shakespeare.lit/globe'
+ type='result'
+ xml:lang='en'>
+ <command xmlns='http://jabber.org/protocol/commands'
+ node='http://jabber.org/protocol/admin#add-user'
+ sessionid='add-user:20040408T0337Z'
+ status='executing'>
+ <x xmlns='jabber:x:data' type='form'>
+ <title>Adding a User</title>
+ <instructions>Fill out this form to add a user.</instructions>
+ <field type='hidden' var='FORM_TYPE'>
+ <value>http://jabber.org/protocol/admin</value>
+ </field>
+ <field label='The Jabber ID for the account to be added'
+ type='jid-single'
+ var='accountjid'>
+ <required/>
+ </field>
+ <field label='The password for this account'
+ type='text-private'
+ var='password'/>
+ <field label='Retype password'
+ type='text-private'
+ var='password-verify'/>
+ <field label='Email address'
+ type='text-single'
+ var='email'/>
+ <field label='Given name'
+ type='text-single'
+ var='given_name'/>
+ <field label='Family name'
+ type='text-single'
+ var='surname'/>
+ </x>
+ </command>
+</iq>
+
+ */
+
+
+ @Override
+ protected Stanza handleGet(IQStanza stanza, ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext) {
+
+ Entity to = stanza.getTo();
+ Entity from = stanza.getFrom();
+
+ if (from == null) {
+ from = sessionContext.getInitiatingEntity();
+ }
+
+ StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza(stanza.getTo(), stanza.getFrom(),
+ IQStanzaType.RESULT, stanza.getID());
+ return stanzaBuilder.build();
+ }
+}
\ No newline at end of file
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandSupport.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandSupport.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandSupport.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandSupport.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.InfoRequest;
+
+import java.util.Collection;
+
+/**
+ * extension point for the ad-hoc command module to retrieve info about commands and invoke them.
+ */
+public interface AdhocCommandSupport {
+
+ /**
+ * handles discovery
+ *
+ *
+ * @param infoRequest
+ * @return
+ */
+ Collection<CommandInfo> getCommandInfosForInfoRequest(InfoRequest infoRequest, boolean hintListAll);
+
+ /**
+ * retrieve handler for a command
+ * @return
+ */
+ AdhocCommandHandler getCommandHandler(String commandNode, Entity executingUser);
+
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsModule.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsModule.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsModule.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsModule.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.modules.DefaultDiscoAwareModule;
+import org.apache.vysper.xmpp.modules.ServerRuntimeContextService;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.Feature;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.Identity;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.InfoElement;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.InfoRequest;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.Item;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.ItemRequestListener;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.ServerInfoRequestListener;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.ServiceDiscoveryRequestException;
+import org.apache.vysper.xmpp.protocol.HandlerDictionary;
+import org.apache.vysper.xmpp.protocol.NamespaceHandlerDictionary;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A module for <a href="http://xmpp.org/extensions/xep-0050.html">XEP-0050 Ad-hoc Commands</a>.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class AdhocCommandsModule extends DefaultDiscoAwareModule
+ implements ItemRequestListener, ServerInfoRequestListener,
+ ServerRuntimeContextService, AdhocCommandsService{
+
+ public static final String ADHOC_COMMANDS = "adhoc_commands";
+ private final Logger logger = LoggerFactory.getLogger(org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandsModule.class);
+
+ protected ServerRuntimeContext serverRuntimeContext;
+
+ protected AdhocCommandIQHandler iqHandler;
+
+ protected final List<AdhocCommandSupport> adhocCommandSupporters = new ArrayList<AdhocCommandSupport>();
+
+ @Override
+ public void initialize(ServerRuntimeContext serverRuntimeContext) {
+ super.initialize(serverRuntimeContext);
+
+ this.serverRuntimeContext = serverRuntimeContext;
+
+ serverRuntimeContext.registerServerRuntimeContextService(this);
+ }
+
+ @Override
+ public String getName() {
+ return "XEP-0050 Ad-hoc Commands";
+ }
+
+ @Override
+ public String getVersion() {
+ return "1.2";
+ }
+
+ /**
+ * Make this object available for disco#items requests.
+ */
+ @Override
+ protected void addItemRequestListeners(List<ItemRequestListener> itemRequestListeners) {
+ itemRequestListeners.add(this);
+ }
+
+ @Override
+ protected void addServerInfoRequestListeners(List<ServerInfoRequestListener> serverInfoRequestListeners) {
+ serverInfoRequestListeners.add(this);
+ }
+
+ /**
+ * Implements the getItemsFor method from the {@link ItemRequestListener} interface.
+ * Makes this modules available via disco#items and returns the associated nodes.
+ *
+ * @see ItemRequestListener#getItemsFor(InfoRequest)
+ */
+ public List<Item> getItemsFor(InfoRequest request) throws ServiceDiscoveryRequestException {
+ if (!NamespaceURIs.XEP0050_ADHOC_COMMANDS.equals(request.getNode())) {
+ return null;
+ }
+
+ List<CommandInfo> allCommandInfos = new ArrayList<CommandInfo>();
+ for (AdhocCommandSupport adhocCommandSupporter : adhocCommandSupporters) {
+ final Collection<CommandInfo> commandInfos = adhocCommandSupporter.getCommandInfosForInfoRequest(request, true);
+ if (commandInfos != null) allCommandInfos.addAll(commandInfos);
+ }
+ if (allCommandInfos.size() == 0) return null; // do not announce when no command available
+
+ // formulate info response from collected command infos
+ List<Item> items = new ArrayList<Item>();
+ for (CommandInfo commandInfo : allCommandInfos) {
+ Entity jid = commandInfo.getJid();
+ if (jid == null) jid = serverRuntimeContext.getServerEnitity();
+
+ String node = commandInfo.getNode();
+ if (node == null) {
+ logger.warn("no node for command info, ignoring. command name = " + commandInfo.getName());
+ continue;
+ }
+
+ String name = commandInfo.getName() == null ? commandInfo.getNode() : commandInfo.getName();
+ items.add(new Item(jid, name, node));
+ }
+
+ return items;
+ }
+
+ public List<InfoElement> getServerInfosFor(InfoRequest request) throws ServiceDiscoveryRequestException {
+ if (adhocCommandSupporters.size() == 0) return null; // do not announce when no command available
+
+ if (StringUtils.isEmpty(request.getNode())) {
+ return Arrays.asList((InfoElement)new Feature(NamespaceURIs.XEP0050_ADHOC_COMMANDS));
+ }
+
+ // info for specific node has been asked
+ List<CommandInfo> allCommandInfos = new ArrayList<CommandInfo>();
+ for (AdhocCommandSupport adhocCommandSupporter : adhocCommandSupporters) {
+ final Collection<CommandInfo> commandInfos = adhocCommandSupporter.getCommandInfosForInfoRequest(request, false);
+ if (commandInfos != null) allCommandInfos.addAll(commandInfos);
+ }
+ if (allCommandInfos.size() == 0) return null; // do not announce when no command available
+
+ final CommandInfo commandInfo = allCommandInfos.get(0);
+ final ArrayList<InfoElement> infoElements = new ArrayList<InfoElement>();
+ infoElements.add(new Identity("automation", "command-node", commandInfo.getName()));
+ infoElements.add(new Feature(NamespaceURIs.XEP0050_ADHOC_COMMANDS));
+ infoElements.add(new Feature(NamespaceURIs.JABBER_X_DATA));
+ return infoElements;
+
+ }
+
+ public String getServiceName() {
+ return ADHOC_COMMANDS;
+ }
+
+ public void registerCommandSupport(AdhocCommandSupport adhocCommandSupport) {
+ adhocCommandSupporters.add(adhocCommandSupport);
+ }
+
+ @Override
+ protected void addHandlerDictionaries(List<HandlerDictionary> dictionary) {
+ iqHandler = new AdhocCommandIQHandler(Collections.unmodifiableCollection(adhocCommandSupporters));
+ dictionary.add(new NamespaceHandlerDictionary(NamespaceURIs.XEP0050_ADHOC_COMMANDS, iqHandler));
+ }
+
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsService.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsService.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsService.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/AdhocCommandsService.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+/**
+ */
+public interface AdhocCommandsService {
+ void registerCommandSupport(AdhocCommandSupport adhocCommandSupport);
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/CommandInfo.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/CommandInfo.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/CommandInfo.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/CommandInfo.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+import org.apache.vysper.xmpp.addressing.Entity;
+
+/**
+ * provides infos about the available command for a specific module
+ */
+public class CommandInfo {
+
+ protected Entity jid;
+ protected String node;
+ protected String name;
+
+ public CommandInfo(Entity jid, String node, String name) {
+ this.jid = jid;
+ this.node = node;
+ this.name = name;
+ }
+
+ public CommandInfo(String node, String name) {
+ this.node = node;
+ this.name = name;
+ }
+
+ public Entity getJid() {
+ return jid;
+ }
+
+ public String getNode() {
+ return node;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/Note.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/Note.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/Note.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0050_adhoc_commands/Note.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,36 @@
+package org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands;
+
+/**
+ * a command note
+ */
+public class Note {
+ public static enum Type { info, warn, error }
+
+ public static Note info(String text) {
+ return new Note(Type.info, text);
+ }
+
+ public static Note warn(String text) {
+ return new Note(Type.warn, text);
+ }
+
+ public static Note error(String text) {
+ return new Note(Type.error, text);
+ }
+
+ protected Type type;
+ protected String text;
+
+ protected Note(Type type, String text) {
+ this.type = type;
+ this.text = text;
+ }
+
+ public Type getType() {
+ return type;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/ServiceAdministrationModule.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/ServiceAdministrationModule.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/ServiceAdministrationModule.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/ServiceAdministrationModule.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.vysper.xmpp.modules.extension.xep0133_service_administration;
+
+import org.apache.vysper.storage.StorageProvider;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.addressing.EntityFormatException;
+import org.apache.vysper.xmpp.addressing.EntityImpl;
+import org.apache.vysper.xmpp.authorization.AccountManagement;
+import org.apache.vysper.xmpp.authorization.UserAuthorization;
+import org.apache.vysper.xmpp.modules.DefaultModule;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandHandler;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandSupport;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandsModule;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AdhocCommandsService;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.CommandInfo;
+import org.apache.vysper.xmpp.modules.extension.xep0133_service_administration.command.AddUserCommandHandler;
+import org.apache.vysper.xmpp.modules.extension.xep0133_service_administration.command.GetOnlineUsersCommandHandler;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.InfoRequest;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A module for <a href="http://xmpp.org/extensions/xep-0133.html">XEP-0133 Service Administration</a>.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class ServiceAdministrationModule extends DefaultModule implements AdhocCommandSupport {
+
+ private final Logger logger = LoggerFactory.getLogger(ServiceAdministrationModule.class);
+
+ public static final String COMMAND_NODE_ADD_USER = "http://jabber.org/protocol/admin#add-user";
+ public static final String COMMAND_GET_ONLINE_USERS_NUM = "http://jabber.org/protocol/admin#get-online-users-num";
+
+ private ServerRuntimeContext serverRuntimeContext;
+
+ protected Collection<Entity> admins = new HashSet<Entity>();
+ protected final Map<String, CommandInfo> allCommandInfos = new HashMap<String, CommandInfo>();
+
+ public ServiceAdministrationModule() {
+ allCommandInfos.put(COMMAND_NODE_ADD_USER, new CommandInfo(COMMAND_NODE_ADD_USER, "Add User"));
+ allCommandInfos.put(COMMAND_GET_ONLINE_USERS_NUM, new CommandInfo(COMMAND_GET_ONLINE_USERS_NUM, "Get Number of Online Users"));
+ }
+
+ /**
+ * Initializes the MUC module, configuring the storage providers.
+ */
+ @Override
+ public void initialize(ServerRuntimeContext serverRuntimeContext) {
+ super.initialize(serverRuntimeContext);
+
+ this.serverRuntimeContext = serverRuntimeContext;
+
+ final AdhocCommandsService adhocCommandsService = (AdhocCommandsService)serverRuntimeContext.getServerRuntimeContextService(AdhocCommandsModule.ADHOC_COMMANDS);
+ adhocCommandsService.registerCommandSupport(this);
+ }
+
+ public void setAddAdminJIDs(Collection<Entity> admins) {
+ this.admins.addAll(admins);
+ }
+
+ public void setAddAdmins(Collection<String> admins) {
+
+ Set<Entity> adminEntities = new HashSet<Entity>();
+ for (String admin : admins) {
+ try {
+ adminEntities.add(EntityImpl.parse(admin));
+ } catch (EntityFormatException e) {
+ logger.error("could not add mal-formed JID as administrator: " + admin);
+ }
+ }
+ this.admins.addAll(adminEntities);
+ }
+
+ @Override
+ public String getName() {
+ return "XEP-0133 Service Administration";
+ }
+
+ @Override
+ public String getVersion() {
+ return "1.1";
+ }
+
+ public Collection<CommandInfo> getCommandInfosForInfoRequest(InfoRequest infoRequest, boolean hintListAll) {
+ if (!admins.contains(infoRequest.getFrom())) {
+ return null;
+ }
+ if (hintListAll) return allCommandInfos.values();
+
+ final CommandInfo commandInfo = allCommandInfos.get(infoRequest.getNode());
+ return (commandInfo == null) ? null : Arrays.asList(commandInfo);
+ }
+
+ public AdhocCommandHandler getCommandHandler(String commandNode, Entity executingUser) {
+ if (executingUser == null || !admins.contains(executingUser)) {
+ return null;
+ }
+ if (commandNode.equals(COMMAND_NODE_ADD_USER)) {
+ final AccountManagement accountManagement = (AccountManagement)serverRuntimeContext.getStorageProvider(AccountManagement.class);
+ if (accountManagement == null) return null;
+ return new AddUserCommandHandler(accountManagement, Arrays.asList(serverRuntimeContext.getServerEnitity().getDomain()));
+ } else if (commandNode.equals(COMMAND_GET_ONLINE_USERS_NUM)) {
+ return new GetOnlineUsersCommandHandler(serverRuntimeContext.getResourceRegistry());
+ }
+ return null;
+ }
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/AddUserCommandHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/AddUserCommandHandler.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/AddUserCommandHandler.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/AddUserCommandHandler.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,92 @@
+package org.apache.vysper.xmpp.modules.extension.xep0133_service_administration.command;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.vysper.xml.fragment.XMLElement;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.authorization.AccountCreationException;
+import org.apache.vysper.xmpp.authorization.AccountManagement;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AbstractAdhocCommandHandler;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.Note;
+import org.apache.vysper.xmpp.stanza.dataforms.DataForm;
+import org.apache.vysper.xmpp.stanza.dataforms.DataFormParser;
+import org.apache.vysper.xmpp.stanza.dataforms.Field;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ */
+public class AddUserCommandHandler extends AbstractAdhocCommandHandler {
+
+ protected AccountManagement accountManagement;
+ protected List<String> allowedDomains;
+
+ public AddUserCommandHandler(AccountManagement accountManagement, List<String> allowedDomains) {
+ this.accountManagement = accountManagement;
+ if (allowedDomains == null || allowedDomains.size() == 0) {
+ throw new IllegalArgumentException("allowed domain list cannot be empty");
+ }
+ this.allowedDomains = allowedDomains;
+ }
+
+ public XMLElement process(List<XMLElement> commandElements, List<Note> notes) {
+ if (commandElements == null || commandElements.size() == 0) {
+ return sendForm();
+ } else {
+ return processForm(commandElements, notes);
+ }
+ }
+
+ protected XMLElement sendForm() {
+ final DataForm dataForm = createFormForm("Adding a User", "Fill out this form to add a user.");
+ dataForm.addField(new Field("The Jabber ID for the account to be added", Field.Type.JID_SINGLE, "accountjid"));
+ dataForm.addField(new Field("The password for this account", Field.Type.TEXT_PRIVATE, "password"));
+ dataForm.addField(new Field("Retype password", Field.Type.TEXT_PRIVATE, "password-verify"));
+ dataForm.addField(new Field("Email address", Field.Type.TEXT_SINGLE, "email"));
+ dataForm.addField(new Field("Given name", Field.Type.TEXT_SINGLE, "given_name"));
+ dataForm.addField(new Field("Family name", Field.Type.TEXT_SINGLE, "surname"));
+
+ return DATA_FORM_ENCODER.getXML(dataForm);
+ }
+
+ protected XMLElement processForm(List<XMLElement> commandElements, List<Note> notes) {
+ if (commandElements.size() != 1) {
+ throw new IllegalStateException("must be an X element");
+ }
+ final DataFormParser dataFormParser = new DataFormParser(commandElements.get(0));
+ final Map<String,Object> valueMap = dataFormParser.extractFieldValues();
+ final Entity accountjid = (Entity)valueMap.get("accountjid");
+ final String password = (String)valueMap.get("password");
+ final String password2 = (String)valueMap.get("password-verify");
+
+ if (accountjid == null || !allowedDomains.contains(accountjid.getDomain())) {
+ notes.add(Note.error("new account must match one of this server's domains, e.g. " + allowedDomains.get(0)));
+ return sendForm();
+ }
+ if (StringUtils.isBlank(password) ||
+ password.equals(accountjid.getFullQualifiedName()) ||
+ password.length() < 8) {
+ notes.add(Note.error("password must have at least 8 chars and must not be the same as the new JID"));
+ return sendForm();
+ }
+ if (!password.equals(password2)) {
+ notes.add(Note.error("passwords did not match"));
+ return sendForm();
+ }
+ if (accountManagement.verifyAccountExists(accountjid)) {
+ notes.add(Note.error("account already exists: " + accountjid));
+ return sendForm();
+ }
+
+ try {
+ accountManagement.addUser(accountjid.getFullQualifiedName(), password);
+ } catch (AccountCreationException e) {
+ notes.add(Note.error("account creation failed for " + accountjid));
+ return sendForm();
+ }
+
+ isExecuting = false;
+ return null;
+ }
+
+}
Added: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/GetOnlineUsersCommandHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/GetOnlineUsersCommandHandler.java?rev=1053331&view=auto
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/GetOnlineUsersCommandHandler.java (added)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0133_service_administration/command/GetOnlineUsersCommandHandler.java Tue Dec 28 12:35:11 2010
@@ -0,0 +1,34 @@
+package org.apache.vysper.xmpp.modules.extension.xep0133_service_administration.command;
+
+import org.apache.vysper.xml.fragment.XMLElement;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.AbstractAdhocCommandHandler;
+import org.apache.vysper.xmpp.modules.extension.xep0050_adhoc_commands.Note;
+import org.apache.vysper.xmpp.stanza.dataforms.DataForm;
+import org.apache.vysper.xmpp.stanza.dataforms.Field;
+import org.apache.vysper.xmpp.state.resourcebinding.ResourceRegistry;
+
+import java.util.List;
+
+/**
+ */
+public class GetOnlineUsersCommandHandler extends AbstractAdhocCommandHandler {
+
+ protected final ResourceRegistry resourceRegistry;
+
+ public GetOnlineUsersCommandHandler(ResourceRegistry resourceRegistry) {
+ this.resourceRegistry = resourceRegistry;
+ }
+
+
+ public XMLElement process(List<XMLElement> commandElements, List<Note> notes) {
+ final long sessionCount = resourceRegistry.getSessionCount();
+
+ final DataForm dataForm = createResultForm();
+ dataForm.addField(new Field("The number of online users", Field.Type.FIXED, "onlineusersnum", Long.toString(sessionCount)));
+
+ isExecuting = false;
+
+ return DATA_FORM_ENCODER.getXML(dataForm);
+ }
+
+}
Modified: mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
URL: http://svn.apache.org/viewvc/mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java?rev=1053331&r1=1053330&r2=1053331&view=diff
==============================================================================
--- mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java (original)
+++ mina/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java Tue Dec 28 12:35:11 2010
@@ -88,6 +88,8 @@ public class NamespaceURIs {
public static final String XEP0045_MUC_USER = "http://jabber.org/protocol/muc#user";
+ public static final String XEP0050_ADHOC_COMMANDS = "http://jabber.org/protocol/commands";
+
public static final String XEP0060_PUBSUB = "http://jabber.org/protocol/pubsub";
public static final String XEP0060_PUBSUB_EVENT = "http://jabber.org/protocol/pubsub#event";
@@ -97,4 +99,6 @@ public class NamespaceURIs {
public static final String XEP0060_PUBSUB_ERRORS = "http://jabber.org/protocol/pubsub#errors";
public static final String XEP0124_BOSH = "http://jabber.org/protocol/httpbind";
+
+ public static final String XEP0133_SERVICE_ADMIN = "http://jabber.org/protocol/admin";
}