diff --git a/htroot/Messages_p.java b/htroot/Messages_p.java index c98a679e7..dfb02a3ac 100644 --- a/htroot/Messages_p.java +++ b/htroot/Messages_p.java @@ -124,6 +124,7 @@ public class Messages_p { prop.put("mode", 1); //view String key = post.get("object", ""); message = switchboard.messageDB.read(key); + if (message == null) throw new NullPointerException("Message with ID " + key + " does not exist"); prop.put("mode_from", message.author()); prop.put("mode_to", message.recipient()); diff --git a/htroot/Messages_p.xml b/htroot/Messages_p.xml new file mode 100644 index 000000000..7243dc947 --- /dev/null +++ b/htroot/Messages_p.xml @@ -0,0 +1,21 @@ + +#(mode)# + +#{messages}# + + #[date]# + #[from]# + #[to]# + + +#{/messages}# + +:: + + #[date]# + #[from]# + #[to]# + + + +#(/mode)# \ No newline at end of file diff --git a/source/de/anomic/soap/build.xml b/source/de/anomic/soap/build.xml index 3f7cce37f..43b62cc82 100644 --- a/source/de/anomic/soap/build.xml +++ b/source/de/anomic/soap/build.xml @@ -125,9 +125,9 @@ - + - + diff --git a/source/de/anomic/soap/httpdSoapHandler.java b/source/de/anomic/soap/httpdSoapHandler.java index f15715644..b5528c70c 100644 --- a/source/de/anomic/soap/httpdSoapHandler.java +++ b/source/de/anomic/soap/httpdSoapHandler.java @@ -152,7 +152,8 @@ public final class httpdSoapHandler extends httpdAbstractHandler implements http "admin=de.anomic.soap.services.AdminService", "blacklist=de.anomic.soap.services.BlacklistService", "share=de.anomic.soap.services.ShareService", - "bookmarks=de.anomic.soap.services.BookmarkService" + "bookmarks=de.anomic.soap.services.BookmarkService", + "messages=de.anomic.soap.services.MessageService" }; /* =============================================================== diff --git a/source/de/anomic/soap/services/MessageService.java b/source/de/anomic/soap/services/MessageService.java new file mode 100644 index 000000000..a180f19a9 --- /dev/null +++ b/source/de/anomic/soap/services/MessageService.java @@ -0,0 +1,321 @@ +//MessageService.java +//------------------------ +//part of YaCy +//(C) by Michael Peter Christen; mc@anomic.de +//first published on http://www.anomic.de +//Frankfurt, Germany, 2005 +// +//this file was contributed by Martin Thelian +//last major change: $LastChangedDate$ by $LastChangedBy$ +//Revision: $LastChangedRevision$ +// +//This program is free software; you can redistribute it and/or modify +//it under the terms of the GNU General Public License as published by +//the Free Software Foundation; either version 2 of the License, or +//(at your option) any later version. +// +//This program is distributed in the hope that it will be useful, +//but WITHOUT ANY WARRANTY; without even the implied warranty of +//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//GNU General Public License for more details. +// +//You should have received a copy of the GNU General Public License +//along with this program; if not, write to the Free Software +//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//Using this software in any meaning (reading, learning, copying, compiling, +//running) means that you agree that the Author(s) is (are) not responsible +//for cost, loss of data or any harm that may be caused directly or indirectly +//by usage of this softare or this documentation. The usage of this software +//is on your own risk. The installation and usage (starting/running) of this +//software may allow other people or application to access your computer and +//any attached devices and is highly dependent on the configuration of the +//software which must be done by the user of the software; the author(s) is +//(are) also not responsible for proper configuration and usage of the +//software, even if provoked by documentation provided together with +//the software. +// +//Any changes to this file according to the GPL as documented in the file +//gpl.txt aside this file in the shipment you received can be done to the +//lines that follows this copyright notice here, but changes must not be +//done inside the copyright notive above. A re-distribution must contain +//the intact and unchanged copyright notice. +//Contributions and changes to the program code must be marked as such. + + +package de.anomic.soap.services; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.axis.AxisFault; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import de.anomic.data.messageBoard; +import de.anomic.plasma.plasmaSwitchboard; +import de.anomic.server.serverObjects; +import de.anomic.soap.AbstractService; +import de.anomic.yacy.yacyClient; +import de.anomic.yacy.yacyCore; +import de.anomic.yacy.yacySeed; + +public class MessageService extends AbstractService { + + /* ===================================================================== + * Used XML Templates + * ===================================================================== */ + private static final String TEMPLATE_MESSAGE_HEADER_LIST_XML = "Messages_p.xml"; + + /* ===================================================================== + * Other used constants + * ===================================================================== */ + private static final String MESSAGES_CATEGORY_REMOTE = "remote"; + + /** + * @return a handler to the YaCy Messages DB + */ + private messageBoard getMessageDB() { + assert (this.switchboard != null) : "Switchboard object is null"; + assert (this.switchboard instanceof plasmaSwitchboard) : "Incorrect switchboard object"; + assert (((plasmaSwitchboard)this.switchboard).messageDB != null) : "Messsage DB is null"; + + return ((plasmaSwitchboard)this.switchboard).messageDB; + } + + /** + * Function to read the identifiers of all messages stored in the message db + * @return an array of message identifiers currently stored in the message DB + * @throws IOException if authentication failed or a DB read error occured + */ + public String[] getMessageIDs() throws IOException { + // extracting the message context + extractMessageContext(AUTHENTICATION_NEEDED); + + // getting the messageDB + messageBoard db = getMessageDB(); + + // loop through the messages and receive the message ids + ArrayList idList = new ArrayList(db.size()); + Iterator i = getMessageDB().keys(MESSAGES_CATEGORY_REMOTE, true); + while (i.hasNext()) { + String messageKey = (String) i.next(); + if (messageKey != null) idList.add(messageKey); + } + + //return array + return (String[]) idList.toArray(new String[idList.size()]); + } + + /** + * Returns a list with the sender, subject and date of all messages stored in the message db + * + * @return a xml document of the following format + *
+	 * <?xml version="1.0" encoding="UTF-8"?>
+	 * <messages>
+	 * 	<message id="remote______2005060901120600">
+	 * 		<date>2005/06/09 01:12:06</date>
+	 * 		<from hash="peerhash">SourcePeerName</from>
+	 * 		<to>DestPeerName</to>
+	 * 		<subject><![CDATA[Message subject]]></subject>
+	 * 	</message>
+	 * </messages>
+	 * 
+ * + * @throws Exception if authentication failed + */ + public Document getMessageHeaderList() throws Exception { + + // extracting the message context + extractMessageContext(AUTHENTICATION_NEEDED); + + // generate the xml document + serverObjects args = new serverObjects(); + args.put("action","list"); + + byte[] result = writeTemplate(TEMPLATE_MESSAGE_HEADER_LIST_XML, args); + + // sending back the result to the client + return this.convertContentToXML(result); + } + + /** + * Function to geht detailes about a message stored in the message db + * @param messageID the identifier of the message to query + * @return a xml document of the following format + *
+	 * <?xml version="1.0" encoding="UTF-8"?>
+	 * <message id="remote______2005060901120600">
+	 * 	<date>2005/06/09 01:12:06</date>
+	 * 	<from hash="peerhash">sourcePeerName</from>
+	 * 	<to>destPeerName</to>
+	 * 	<subject><![CDATA[Test-Subject]]></subject>
+	 * 	<message><![CDATA[Message-Body]]>
+	 * </message>
+	 * 
+ * + * @throws Exception if authentication failed + */ + public Document getMessage(String messageID) throws Exception { + + // extracting the message context + extractMessageContext(AUTHENTICATION_NEEDED); + if (messageID == null || messageID.length() == 0) throw new IllegalArgumentException("The message id must not be null or empty."); + + // generate the xml document + serverObjects args = new serverObjects(); + args.put("action","view"); + args.put("object",messageID); + + byte[] result = writeTemplate(TEMPLATE_MESSAGE_HEADER_LIST_XML, args); + + // sending back the result to the client + return this.convertContentToXML(result); + } + + /** + * Function to delete a message + * @param messageID the message identifier of the message that should be deleted + * @throws AxisFault if authentication failed or the message ID is unknown + */ + public void deleteMessage(String messageID) throws AxisFault { + // extracting the message context + extractMessageContext(AUTHENTICATION_NEEDED); + if (messageID == null || messageID.length() == 0) throw new IllegalArgumentException("The message id must not be null or empty."); + + // getting the messageDB + messageBoard db = getMessageDB(); + + // check if the message exists + if (db.read(messageID) == null) throw new AxisFault("Message with ID " + messageID + " does not exist."); + + // delete the message + db.remove(messageID); + } + + /** + * Function to delete multiple messages + * @param messageIDs an array of message ids + * @throws AxisFault if authentication failed or one of the message IDs is unknown + */ + public void deleteMessages(String[] messageIDs) throws AxisFault { + if (messageIDs == null || messageIDs.length == 0) throw new IllegalArgumentException("The message id array must not be null or empty."); + + // loop through the ids + for (int i=0; i < messageIDs.length; i++) { + String nextID = messageIDs[i]; + if (nextID == null || nextID.length() == 0) throw new IllegalArgumentException("The message id at position " + i + " is null or empty."); + + this.deleteMessage(nextID); + } + } + + /** + * A function to check if the destination peer will accept a message of this peer. + * @param destinationPeerHash the peer hash of the destination peer + * @return a XML document of the following format + *
+	 * <?xml version="1.0" encoding="UTF-8"?>
+	 * <messageSendPermission>
+	 * 	<permission>true</permission>
+	 * 	<response>Welcome to my peer!</response>
+	 * 	<messageSize>10240</messageSize>
+	 * 	<attachmentsize>0</attachmentsize>
+	 * </messageSendPermission>
+	 * 
+ * The tag permission specifies if we are allowed to send a messag to this peer. Response is a textual + * description why we are allowed or not allowed to send a message. messageSize specifies the maximum + * allowed message size. attachmentsize specifies the maximum attachment size accepted. + * + * @throws AxisFault if authentication failed or the destination peer is not reachable + * @throws ParserConfigurationException if xml generation failed + */ + public Document getMessageSendPermission(String destinationPeerHash) throws AxisFault, ParserConfigurationException { + // extracting the message context + extractMessageContext(AUTHENTICATION_NEEDED); + if (destinationPeerHash == null || destinationPeerHash.length() == 0) throw new IllegalArgumentException("The destination peer hash must not be null or empty."); + + // get the peer from the db + yacySeed targetPeer = yacyCore.seedDB.getConnected(destinationPeerHash); + if (targetPeer == null) throw new AxisFault("The destination peer is not connected"); + + // check for permission to send message + HashMap result = yacyClient.permissionMessage(destinationPeerHash); + if (result == null) throw new AxisFault("No response received from peer"); + + boolean accepted = false; + String reason = "Unknown reason"; + if (result.containsKey("response")) { + String response = (String) result.get("response"); + if (response.equals("-1")) { + accepted = false; + reason = "request rejected"; + } else { + accepted = true; + reason = response; + } + } + + // return XML Document + Element xmlElement = null, xmlRoot; + Document xmlDoc = createNewXMLDocument("messageSendPermission"); + xmlRoot = xmlDoc.getDocumentElement(); + + xmlElement = xmlDoc.createElement("permission"); + xmlElement.appendChild(xmlDoc.createTextNode(Boolean.toString(accepted))); + xmlRoot.appendChild(xmlElement); + + xmlElement = xmlDoc.createElement("response"); + xmlElement.appendChild(xmlDoc.createTextNode(reason)); + xmlRoot.appendChild(xmlElement); + + xmlElement = xmlDoc.createElement("messageSize"); + xmlElement.appendChild(xmlDoc.createTextNode((String)result.get("messagesize"))); + xmlRoot.appendChild(xmlElement); + + xmlElement = xmlDoc.createElement("attachmentsize"); + xmlElement.appendChild(xmlDoc.createTextNode((String)result.get("attachmentsize"))); + xmlRoot.appendChild(xmlElement); + + return xmlDoc; + } + + /** + * Function to send a message to a remote peer + * @param destinationPeerHash the peer hash of the remot peer + * @param subject the message subject + * @param message the message body + * + * @return the a response status message of the remote peer. + * + * @throws AxisFault if authentication failed + */ + public String sendMessage(String destinationPeerHash, String subject, String message) throws AxisFault { + // extracting the message context + extractMessageContext(AUTHENTICATION_NEEDED); + if (destinationPeerHash == null || destinationPeerHash.length() == 0) throw new IllegalArgumentException("The destination peer hash must not be null or empty."); + if (subject == null || subject.length() == 0) throw new IllegalArgumentException("The subject must not be null or empty."); + if (message == null || message.length() == 0) throw new IllegalArgumentException("The message body must not be null or empty."); + + // convert the string into a byte array + byte[] mb; + try { + mb = message.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + mb = message.getBytes(); + } + + // send the message to the remote peer + HashMap result = yacyClient.postMessage(destinationPeerHash, subject, mb); + + // get the peer resonse + if (result == null) throw new AxisFault("No response received from peer"); + return (String) (result.containsKey("response") ? result.get("response") : "Unknown response"); + } +} diff --git a/source/de/anomic/soap/services/messages.wsdl b/source/de/anomic/soap/services/messages.wsdl new file mode 100644 index 000000000..2396851c3 --- /dev/null +++ b/source/de/anomic/soap/services/messages.wsdl @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/de/anomic/soap/services/MessageServiceTest.java b/test/de/anomic/soap/services/MessageServiceTest.java new file mode 100644 index 000000000..8b0a8bd37 --- /dev/null +++ b/test/de/anomic/soap/services/MessageServiceTest.java @@ -0,0 +1,62 @@ +package de.anomic.soap.services; + +import java.rmi.RemoteException; + +import javax.xml.rpc.ServiceException; + +import org.apache.axis.utils.XMLUtils; +import org.w3c.dom.Document; + +import yacy.soap.messages.MessageService; +import yacy.soap.messages.MessageServiceServiceLocator; + + + +public class MessageServiceTest extends AbstractServiceTest { + + protected void createServiceClass() throws ServiceException { + // construct Soap object + MessageServiceServiceLocator locator = new MessageServiceServiceLocator(); + locator.setmessagesEndpointAddress(getBaseServiceURL() + "messages"); + + service = locator.getmessages(); + } + + public void testGetMessageIDs() throws RemoteException { + MessageService ms = ((MessageService)service); + String[] IDs = ms.getMessageIDs(); + + StringBuffer idList = new StringBuffer(); + for (int i=0; i < IDs.length; i++) { + if (i > 0) idList.append(", "); + idList.append(IDs[i]); + } + + System.out.println(idList); + } + + public void testGetMessageHeaderList() throws RemoteException { + MessageService ms = ((MessageService)service); + Document xml = ms.getMessageHeaderList(); + System.out.println(XMLUtils.DocumentToString(xml)); + } + + public void testMessage() throws RemoteException { + MessageService ms = ((MessageService)service); + + // get message IDs + String[] IDs = ms.getMessageIDs(); + + if (IDs != null && IDs.length > 0) { + Document xml = ms.getMessage(IDs[0]); + System.out.println(XMLUtils.DocumentToString(xml)); + } + } + + public void testGetMessageSendPermission() throws RemoteException { + MessageService ms = ((MessageService)service); + + Document xml = ms.getMessageSendPermission("mseSVGrNKKnw"); + System.out.println(XMLUtils.DocumentToString(xml)); + } +}