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";
 }