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 2009/06/13 19:20:45 UTC

svn commit: r784437 - in /mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper: storage/jcr/ storage/jcr/privatedata/ xmpp/modules/extension/xep0049_privatedata/ xmpp/protocol/

Author: berndf
Date: Sat Jun 13 17:20:45 2009
New Revision: 784437

URL: http://svn.apache.org/viewvc?rev=784437&view=rev
Log:
[vysper] patch contributed by David Phillips. Many thanks.
(VYSPER-72) Implement XEP-0049 Private XML Storage

Added:
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/privatedata/
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/privatedata/JcrPrivateDataPersistenceManager.java
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataIQHandler.java
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataModule.java
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataPersistenceManager.java
Modified:
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/JcrStorageProviderRegistry.java
    mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java

Modified: mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/JcrStorageProviderRegistry.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/JcrStorageProviderRegistry.java?rev=784437&r1=784436&r2=784437&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/JcrStorageProviderRegistry.java (original)
+++ mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/JcrStorageProviderRegistry.java Sat Jun 13 17:20:45 2009
@@ -20,6 +20,7 @@
 package org.apache.vysper.storage.jcr;
 
 import org.apache.vysper.storage.OpenStorageProviderRegistry;
+import org.apache.vysper.storage.jcr.privatedata.JcrPrivateDataPersistenceManager;
 import org.apache.vysper.storage.jcr.roster.JcrRosterManager;
 import org.apache.vysper.storage.jcr.user.JcrUserManagement;
 import org.apache.vysper.storage.jcr.vcardtemp.JcrVcardTempPersistenceManager;
@@ -34,6 +35,7 @@
         add(new JcrUserManagement(JcrStorage.getInstance()));
         add(new JcrRosterManager(JcrStorage.getInstance()));
         add(new JcrVcardTempPersistenceManager(JcrStorage.getInstance()));
+        add(new JcrPrivateDataPersistenceManager(JcrStorage.getInstance()));
     }
 
 }

Added: mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/privatedata/JcrPrivateDataPersistenceManager.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/privatedata/JcrPrivateDataPersistenceManager.java?rev=784437&view=auto
==============================================================================
--- mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/privatedata/JcrPrivateDataPersistenceManager.java (added)
+++ mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/storage/jcr/privatedata/JcrPrivateDataPersistenceManager.java Sat Jun 13 17:20:45 2009
@@ -0,0 +1,93 @@
+/*
+ *  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.storage.jcr.privatedata;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.vysper.storage.jcr.JcrStorage;
+import org.apache.vysper.storage.jcr.JcrStorageException;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.modules.extension.xep0049_privatedata.PrivateDataPersistenceManager;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class JcrPrivateDataPersistenceManager implements PrivateDataPersistenceManager {
+
+    final Logger logger = LoggerFactory.getLogger(JcrPrivateDataPersistenceManager.class);
+
+    protected JcrStorage jcrStorage;
+
+    public JcrPrivateDataPersistenceManager(JcrStorage jcrStorage) {
+        this.jcrStorage = jcrStorage;
+    }
+
+    public boolean isAvailable() {
+        Session session = null;
+        try {
+            session = jcrStorage.getRepositorySession();
+            return session != null;
+        }
+        catch (JcrStorageException e) {
+            return false;
+        }
+    }
+
+    public String getPrivateData(Entity entity, String key) {
+        Node entityNode = getEntityNodeSave(entity, false);
+        if (entityNode == null) return null;
+        try {
+            return entityNode.getProperty(key).getString();
+        }
+        catch (RepositoryException e) {
+            return null;
+        }
+    }
+
+    public boolean setPrivateData(Entity entity, String key, String xml) {
+        Node entityNode = getEntityNodeSave(entity, true);
+        try {
+            entityNode.setProperty(key, xml);
+            entityNode.save();
+            logger.info("JCR node created: " + entityNode);
+            return true;
+        }
+        catch (RepositoryException e) {
+            return false;
+        }
+    }
+
+    private Node getEntityNodeSave(Entity entity, boolean createIfMissing) {
+        Node entityNode;
+        try {
+            entityNode = jcrStorage.getEntityNode(entity.getBareJID(), NamespaceURIs.PRIVATE_DATA, createIfMissing);
+        }
+        catch (JcrStorageException e) {
+            return null;
+        }
+        if (entityNode == null) return null;
+        return entityNode;
+    }
+}

Added: mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataIQHandler.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataIQHandler.java?rev=784437&view=auto
==============================================================================
--- mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataIQHandler.java (added)
+++ mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataIQHandler.java Sat Jun 13 17:20:45 2009
@@ -0,0 +1,166 @@
+/*
+ *  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.xep0049_privatedata;
+
+import org.apache.vysper.compliance.SpecCompliant;
+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.protocol.StreamErrorCondition;
+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 org.apache.vysper.xmpp.xmlfragment.Attribute;
+import org.apache.vysper.xmpp.xmlfragment.Renderer;
+import org.apache.vysper.xmpp.xmlfragment.XMLElement;
+
+/**
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+@SpecCompliant(spec = "xep-0049", status = SpecCompliant.ComplianceStatus.FINISHED, coverage = SpecCompliant.ComplianceCoverage.COMPLETE)
+public class PrivateDataIQHandler extends DefaultIQHandler {
+
+    protected PrivateDataPersistenceManager persistenceManager;
+
+    public void setPersistenceManager(PrivateDataPersistenceManager persistenceManager) {
+        this.persistenceManager = persistenceManager;
+    }
+
+    @Override
+    protected boolean verifyNamespace(Stanza stanza) {
+        return verifyInnerNamespace(stanza, NamespaceURIs.PRIVATE_DATA);
+    }
+
+    @Override
+    protected boolean verifyInnerElement(Stanza stanza) {
+        return verifyInnerElementWorker(stanza, "query");
+    }
+
+    @Override
+    protected Stanza handleSet(IQStanza stanza, ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext) {
+        // Get From
+        Entity to = stanza.getTo();
+        Entity from = stanza.getFrom();
+        if (from == null) {
+            from = sessionContext.getInitiatingEntity();
+        }
+
+        // Not null, and not addressed to itself
+        if (to != null && !to.getBareJID().equals(sessionContext.getInitiatingEntity().getBareJID())) {
+            return ServerErrorResponses.getInstance().getStreamError(StreamErrorCondition.BAD_FORMAT, null, "Private data only modifiable by the owner", null);
+        }
+
+        XMLElement queryElement = stanza.getFirstInnerElement();
+
+        // Example 4: http://xmpp.org/extensions/xep-0049.html
+        // Query element must have a child element with a non-null namespace
+        if (queryElement.getInnerElements().size() != 1) {
+            return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.NOT_ACCEPTABLE, stanza, StanzaErrorType.MODIFY, "query's child element is missing", null, null);
+        }
+        XMLElement x = queryElement.getFirstInnerElement();
+        String ns = x.getAttribute("xmlns").getValue();
+        if (ns == null) {
+            return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.NOT_ACCEPTABLE, stanza, StanzaErrorType.MODIFY, "no namespace", null, null);
+        }
+
+        // No persistancy Manager
+        if (persistenceManager == null) {
+            return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.INTERNAL_SERVER_ERROR, stanza, StanzaErrorType.WAIT, "internal storage inaccessible", null, null);
+        }
+
+        String queryKey = getKey(x);
+        String queryContent = new Renderer(queryElement).getComplete();
+        boolean success = persistenceManager.setPrivateData(from, queryKey, queryContent);
+
+        if (success) {
+            return StanzaBuilder.createIQStanza(null, from, IQStanzaType.RESULT, stanza.getID()).getFinalStanza();
+        } else {
+            return StanzaBuilder.createIQStanza(null, from, IQStanzaType.ERROR, stanza.getID()).getFinalStanza();
+        }
+    }
+
+    @Override
+    protected Stanza handleGet(IQStanza stanza, ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext) {
+        Entity to = stanza.getTo();
+        Entity from = stanza.getFrom();
+        if (from == null) {
+            from = sessionContext.getInitiatingEntity();
+        }
+
+        // Not null, and not addressed to itself
+        if (to != null && !to.getBareJID().equals(sessionContext.getInitiatingEntity().getBareJID())) {
+            return ServerErrorResponses.getInstance().getStreamError(StreamErrorCondition.BAD_FORMAT, null, "can only view your data", null);
+        }
+
+        XMLElement queryElement = stanza.getFirstInnerElement();
+        XMLElement x = queryElement.getFirstInnerElement();
+        if (x == null) {
+            return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.NOT_ACCEPTABLE, stanza, StanzaErrorType.MODIFY, "query's child element missing", null, null);
+        }
+
+        // No persistancy Manager
+        if (persistenceManager == null) {
+            return ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.INTERNAL_SERVER_ERROR, stanza, StanzaErrorType.WAIT, "internal storage inaccessible", null, null);
+        }
+
+        String queryKey = getKey(x);
+        String privateDataXML = persistenceManager.getPrivateData(from, queryKey);
+
+        StanzaBuilder stanzaBuilder = StanzaBuilder.createIQStanza(stanza.getTo(), stanza.getFrom(), IQStanzaType.RESULT, stanza.getID());
+        if (privateDataXML == null) {
+            stanzaBuilder.startInnerElement(x.getName());
+            for (Attribute a : x.getAttributes()) {
+                stanzaBuilder.addAttribute(a);
+            }
+            stanzaBuilder.endInnerElement();
+        } else {
+            stanzaBuilder.addText(privateDataXML);
+        }
+        return stanzaBuilder.getFinalStanza();
+    }
+
+    /**
+     * Create a property name that is unique for this query. eg this XMLElement:
+     * <storage xmlns="storage:bookmarks"> is converted into this string:
+     * storage-storage-bookmarks
+     */
+    private String getKey(XMLElement x) {
+        StringBuilder queryKey = new StringBuilder();
+        queryKey.append(x.getName());
+        queryKey.append("-");
+        queryKey.append(x.getAttribute("xmlns").getValue());
+
+        // Some characters are not valid for property names
+        for (int i = 0; i < queryKey.length(); i++) {
+            char c = queryKey.charAt(i);
+            if (c == ' ' || c == ':') {
+                queryKey.setCharAt(i, '-');
+            }
+        }
+        return queryKey.toString();
+    }
+
+}

Added: mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataModule.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataModule.java?rev=784437&view=auto
==============================================================================
--- mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataModule.java (added)
+++ mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataModule.java Sat Jun 13 17:20:45 2009
@@ -0,0 +1,87 @@
+/*
+ *  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.xep0049_privatedata;
+
+import org.apache.vysper.xmpp.modules.DefaultDiscoAwareModule;
+import org.apache.vysper.xmpp.modules.servicediscovery.management.Feature;
+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.ServerInfoRequestListener;
+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.List;
+
+/**
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class PrivateDataModule extends DefaultDiscoAwareModule implements ServerInfoRequestListener {
+
+    final Logger logger = LoggerFactory.getLogger(PrivateDataModule.class);
+    
+    protected PrivateDataIQHandler iqHandler = new PrivateDataIQHandler();
+
+    @Override
+    public void initialize(ServerRuntimeContext serverRuntimeContext) {
+        super.initialize(serverRuntimeContext);
+
+        PrivateDataPersistenceManager persistenceManager = (PrivateDataPersistenceManager) serverRuntimeContext.getStorageProvider(PrivateDataPersistenceManager.class);
+        if (persistenceManager == null) {
+            logger.error("no PrivateDataPersistenceManager found");
+        } else if (!persistenceManager.isAvailable()) {
+            logger.warn("PrivateDataPersistenceManager not available");
+        } else {
+            iqHandler.setPersistenceManager(persistenceManager);
+        }
+    }
+
+    @Override
+    public String getName() {
+        return "XEP-0049 Private Data";
+    }
+
+    @Override
+    public String getVersion() {
+        return "1.2";
+    }
+
+    @Override
+    protected void addServerInfoRequestListeners(List<ServerInfoRequestListener> serverInfoRequestListeners) {
+        serverInfoRequestListeners.add(this);
+    }
+    
+    public List<InfoElement> getServerInfosFor(InfoRequest request) {
+        List<InfoElement> infoElements = new ArrayList<InfoElement>();
+        infoElements.add(new Feature(NamespaceURIs.PRIVATE_DATA));
+        return infoElements;
+    }
+    
+    @Override
+    protected void addHandlerDictionaries(List<HandlerDictionary> dictionary) {
+        iqHandler = new PrivateDataIQHandler();
+        dictionary.add(new NamespaceHandlerDictionary(NamespaceURIs.PRIVATE_DATA, iqHandler));
+    }
+}

Added: mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataPersistenceManager.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataPersistenceManager.java?rev=784437&view=auto
==============================================================================
--- mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataPersistenceManager.java (added)
+++ mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0049_privatedata/PrivateDataPersistenceManager.java Sat Jun 13 17:20:45 2009
@@ -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.xep0049_privatedata;
+
+import org.apache.vysper.storage.StorageProvider;
+import org.apache.vysper.xmpp.addressing.Entity;
+
+/**
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public interface PrivateDataPersistenceManager extends StorageProvider {
+
+    /**
+     * @return if the persistene manager is ready to operate
+     */
+    boolean isAvailable();
+
+    String getPrivateData(Entity entity, String key);
+
+    boolean setPrivateData(Entity entity, String key, String xml);
+
+}

Modified: mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java?rev=784437&r1=784436&r2=784437&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java (original)
+++ mina/sandbox/vysper/trunk/src/main/java/org/apache/vysper/xmpp/protocol/NamespaceURIs.java Sat Jun 13 17:20:45 2009
@@ -44,6 +44,7 @@
     public static final String JABBER_IQ_VERSION = "jabber:iq:version";
     public static final String JABBER_IQ_TIME = "jabber:iq:time";
     public static final String JABBER_X_DATA = "jabber:x:data";
+    public static final String PRIVATE_DATA = "jabber:iq:private";
     public static final String URN_XMPP_TIME = "urn:xmpp:time";
     public static final String VCARD_TEMP  = "vcard-temp";
     public static final String XEP0030_SERVICE_DISCOVERY_ITEMS = "http://jabber.org/protocol/disco#items";