2 * Copyright (c) 2002-2007 Sun Microsystems, Inc. All rights reserved.
4 * The Sun Project JXTA(TM) Software License
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
16 * 3. The end-user documentation included with the redistribution, if any, must
17 * include the following acknowledgment: "This product includes software
18 * developed by Sun Microsystems, Inc. for JXTA(TM) technology."
19 * Alternately, this acknowledgment may appear in the software itself, if
20 * and wherever such third-party acknowledgments normally appear.
22 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
23 * not be used to endorse or promote products derived from this software
24 * without prior written permission. For written permission, please contact
25 * Project JXTA at http://www.jxta.org.
27 * 5. Products derived from this software may not be called "JXTA", nor may
28 * "JXTA" appear in their name, without prior written permission of Sun.
30 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
32 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
33 * MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
36 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
37 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
38 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
39 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 * JXTA is a registered trademark of Sun Microsystems, Inc. in the United
42 * States and other countries.
44 * Please see the license information page at :
45 * <http://www.jxta.org/project/www/license.html> for instructions on use of
46 * the license in source files.
48 * ====================================================================
50 * This software consists of voluntary contributions made by many individuals
51 * on behalf of Project JXTA. For more information on Project JXTA, please see
52 * http://www.jxta.org.
54 * This license is based on the BSD license adopted by the Apache Foundation.
57 package net.jxta.impl.protocol;
60 import net.jxta.document.*;
61 import net.jxta.id.ID;
62 import net.jxta.id.IDFactory;
63 import net.jxta.pipe.PipeID;
64 import net.jxta.protocol.PeerAdvertisement;
65 import net.jxta.protocol.PipeResolverMessage;
66 import java.util.logging.Level;
67 import net.jxta.logging.Logging;
68 import java.util.logging.Logger;
70 import java.io.IOException;
71 import java.io.StringReader;
73 import java.net.URISyntaxException;
74 import java.util.Enumeration;
79 * This class implements {@link net.jxta.protocol.PipeResolverMessage} by
80 * providing {@link #initialize(Element)} and {@link #getDocument(MimeMediaType)}
83 * <p/>It implements the PipeResolver message for the standard Pipe
84 * Binding Protocol (PBP) with the following schema:
87 * <xs:element name="jxta:PipeResolver" type="jxta:PipeResolver"/>
89 * <xs:simpleType name="PipeResolverMsgType">
90 * <xs:restriction base="xs:string">
92 * <xs:enumeration value="Query"/>
94 * <xs:enumeration value="Answer"/>
95 * </xs:restriction>
98 * <xs:complexType name="PipeResolver">
100 * <xs:element name="MsgType" type="jxta:PipeResolverMsgType"/>
101 * <xs:element name="PipeId" type="jxta:JXTAID"/>
102 * <xs:element name="Type" type="xs:string"/>
104 * <!-- used in the query -->
105 * <xs:element name="Cached" type="xs:boolean" default="true" minOccurs="0"/>
106 * <xs:element name="Peer" type="jxta:JXTAID" minOccurs="0" maxOccurs="unbounded"/>
108 * <!-- used in the answer -->
109 * <xs:element name="Found" minOccurs="0" type="xs:boolean"/>
110 * <!-- This should refer to a peer adv, but is instead a whole doc -->
111 * <xs:element name="PeerAdv" minOccurs="0" type="xs:string" />
113 * </xs:complexType>
116 * @see net.jxta.pipe.PipeService
117 * @see net.jxta.impl.pipe.PipeServiceImpl
118 * @see <a href="https://jxta-spec.dev.java.net/nonav/JXTAProtocols.html#proto-pbp" target="_blank">JXTA Protocols Specification : Pipe Binding Protocol</a>
120 public class PipeResolverMsg extends PipeResolverMessage {
125 private final static transient Logger LOG = Logger.getLogger(PipeResolverMsg.class.getName());
127 private final static String MsgTypeTag = "MsgType";
128 private final static String PipeIdTag = "PipeId";
129 private final static String PipeTypeTag = "Type";
130 private final static String PeerIdTag = "Peer";
131 private final static String PeerAdvTag = "PeerAdv";
132 private final static String FoundTag = "Found";
134 private final static String QueryMsgType = "Query";
135 private final static String AnswerMsgType = "Answer";
137 public PipeResolverMsg() {}
139 public PipeResolverMsg(Element root) {
143 private void initialize(Element root) {
144 if (!TextElement.class.isInstance(root)) {
145 throw new IllegalArgumentException(getClass().getName() + " only supports TextElement");
148 TextElement doc = (TextElement) root;
150 String docName = doc.getName();
152 if (!docName.equals(getMessageType())) {
153 throw new IllegalArgumentException(
154 "Could not construct : " + getClass().getName() + "from doc containing a " + docName);
157 Enumeration each = doc.getChildren();
159 while (each.hasMoreElements()) {
160 TextElement elem = (TextElement) each.nextElement();
162 if (elem.getName().equals(MsgTypeTag)) {
163 String msgtype = elem.getTextValue();
165 if (msgtype.equals(QueryMsgType)) {
166 setMsgType(PipeResolverMessage.MessageType.QUERY);
167 } else if (msgtype.equals(AnswerMsgType)) {
168 setMsgType(PipeResolverMessage.MessageType.ANSWER);
170 throw new IllegalArgumentException("Unexpected Message Type in parsing.");
175 if (elem.getName().equals(PipeIdTag)) {
177 URI pipeID = new URI(elem.getTextValue());
179 setPipeID(IDFactory.fromURI(pipeID));
180 } catch (URISyntaxException badID) {
181 throw new IllegalArgumentException("Bad pipe ID in message");
186 if (elem.getName().equals(PipeTypeTag)) {
187 setPipeType(elem.getTextValue());
191 if (elem.getName().equals(PeerIdTag)) {
193 URI peerID = new URI(elem.getTextValue());
195 addPeerID(IDFactory.fromURI(peerID));
196 } catch (URISyntaxException badID) {
197 throw new IllegalArgumentException("Bad peer ID in message");
202 if (elem.getName().equals(FoundTag)) {
203 setFound(Boolean.valueOf(elem.getTextValue()));
207 // let's check whether the responder sent us a adv
208 if (elem.getName().equals(PeerAdvTag)) {
209 String peerAdv = elem.getTextValue();
213 (PeerAdvertisement) AdvertisementFactory.newAdvertisement(MimeMediaType.XMLUTF8
215 new StringReader(peerAdv)));
216 } catch (IOException caught) {
217 if (Logging.SHOW_FINE && LOG.isLoggable(Level.FINE)) {
218 LOG.log(Level.FINE, "Malformed peer adv in message", caught);
220 throw new IllegalArgumentException("Malformed peer adv in message : " + caught.getMessage());
227 PipeResolverMessage.MessageType msgType = getMsgType();
229 if (null == msgType) {
230 throw new IllegalArgumentException("Message type was never set!");
233 ID pipeID = getPipeID();
235 if ((null == pipeID) || ID.nullID.equals(pipeID) || !(pipeID instanceof PipeID)) {
236 throw new IllegalArgumentException("Input Pipe ID not set or invalid");
239 if (null == getPipeType()) {
240 throw new IllegalArgumentException("Pipe type was never set!");
243 // Response extra checks
244 if (PipeResolverMessage.MessageType.ANSWER.equals(msgType)) {
245 if (getPeerIDs().isEmpty()) {
246 throw new IllegalArgumentException("An answer without responses is invalid");
252 * Creates a document out of the message.
254 * @param encodeAs The document representation format requested.
255 * @return the message as a document.
258 public Document getDocument(MimeMediaType encodeAs) {
259 StructuredTextDocument doc = (StructuredTextDocument)
260 StructuredDocumentFactory.newStructuredDocument(encodeAs, getMessageType());
262 if (doc instanceof Attributable) {
263 ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org");
266 PipeResolverMessage.MessageType msgType = getMsgType();
268 if (null == msgType) {
269 throw new IllegalStateException("Message type was never set!");
272 ID pipeID = getPipeID();
274 if ((null == pipeID) || ID.nullID.equals(pipeID) || !(pipeID instanceof PipeID)) {
275 throw new IllegalStateException("Pipe ID not set or invalid.");
278 String pipeType = getPipeType();
280 if ((null == pipeType) || (0 == pipeType.trim().length())) {
281 throw new IllegalStateException("Pipe type was never set or is invalid.");
286 if (PipeResolverMessage.MessageType.QUERY.equals(msgType)) {
287 element = doc.createElement(MsgTypeTag, QueryMsgType);
288 } else if (PipeResolverMessage.MessageType.ANSWER.equals(msgType)) {
289 element = doc.createElement(MsgTypeTag, AnswerMsgType);
291 throw new IllegalStateException("Unknown message type :" + msgType.toString());
293 doc.appendChild(element);
295 element = doc.createElement(PipeIdTag, pipeID.toString());
296 doc.appendChild(element);
298 if ((pipeType != null) && (0 != pipeType.length())) {
299 element = doc.createElement(PipeTypeTag, pipeType);
300 doc.appendChild(element);
303 // Write the peer ids.
304 Set peers = getPeerIDs();
306 if (PipeResolverMessage.MessageType.ANSWER.equals(msgType) && peers.isEmpty()) {
307 throw new IllegalStateException("An ANSWER message must contain at least one peer as part of the response.");
310 for (Object peer : peers) {
311 ID aPeer = (ID) peer;
313 element = doc.createElement(PeerIdTag, aPeer.toString());
314 doc.appendChild(element);
317 if (PipeResolverMessage.MessageType.QUERY.equals(msgType)) {// nothing for now...
318 } else if (PipeResolverMessage.MessageType.ANSWER.equals(msgType)) {
319 element = doc.createElement(FoundTag, (isFound() ? Boolean.TRUE : Boolean.FALSE).toString());
320 doc.appendChild(element);
322 PeerAdvertisement peerAdv = getInputPeerAdv();
324 if (peerAdv != null) {
325 if (!peers.contains(peerAdv.getPeerID())) {
326 throw new IllegalStateException(
327 "Provided Peer Advertisement does not refer to one of the peers in the response list.");
330 StructuredTextDocument asDoc = (StructuredTextDocument) peerAdv.getDocument(MimeMediaType.XMLUTF8);
332 element = doc.createElement(PeerAdvTag, asDoc.toString());
333 doc.appendChild(element);
336 throw new IllegalStateException("Unknown message type :" + msgType.toString());