/** * Constructs an instance of {@link StructuredDocument} matching the mime-type specified by the * <CODE>mimetype</CODE> parameter. The <CODE>doctype</CODE> parameter identifies the base type of * the {@link StructuredDocument}. * * @param mimetype Specifies the mime media type to be associated with the {@link * StructuredDocument} to be created. * @param reader A Reader from which the document will be constructed. * @return StructuredDocument The instance of {@link StructuredDocument} or null if it could not * be created. * @throws IOException If there is a problem reading from the stream. * @throws NoSuchElementException if the mime-type has not been registerd. * @throws UnsupportedOperationException if the mime-type provided is not a text oriented * mimetype. */ public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, Reader reader) throws IOException { if (!factory.loadedProperty) { factory.loadedProperty = factory.doLoadProperty(); } Instantiator instantiator = (Instantiator) factory.getInstantiator(mimetype.getMimeMediaType()); if (!(instantiator instanceof TextInstantiator)) { // XXX 20020502 [email protected] we could probably do something // really inefficient that would allow it to work, but better not to. // if ReaderInputStream existed, it would be easy to do. if (LOG.isEnabledFor(Level.WARN)) LOG.warn( "Document Class '" + instantiator.getClass().getName() + "' associated with '" + mimetype + "' is not a text oriented document"); throw new UnsupportedOperationException( "Document Class '" + instantiator.getClass().getName() + "' associated with '" + mimetype + "' is not a text oriented document"); } return ((TextInstantiator) instantiator).newInstance(mimetype, reader); }
/** * Constructs an instance of {@link StructuredDocument} matching the mime-type specified by the * <CODE>mimetype</CODE> parameter. The <CODE>doctype</CODE> parameter identifies the base type of * the {@link StructuredDocument}. * * @param mimetype Specifies the mime media type to be associated with the {@link * StructuredDocument} to be created. * @param doctype Specifies the root type of the {@link StructuredDocument} to be created. * @return StructuredDocument The instance of {@link StructuredDocument} or null if it could not * be created. * @throws NoSuchElementException invalid mime-media-type */ public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, String doctype) { if (!factory.loadedProperty) { factory.loadedProperty = factory.doLoadProperty(); } Instantiator instantiator = (Instantiator) factory.getInstantiator(mimetype.getMimeMediaType()); return instantiator.newInstance(mimetype, doctype); }
/** * Constructs an instance of {@link StructuredDocument} matching the mime-type specified by the * <CODE>mimetype</CODE> parameter. The <CODE>doctype</CODE> parameter identifies the base type of * the {@link StructuredDocument}. * * @param mimetype Specifies the mime media type to be associated with the {@link * StructuredDocument} to be created. * @param stream Contains an InputStream from which the document will be constructed. * @return StructuredDocument The instance of {@link StructuredDocument} or null if it could not * be created. * @throws IOException If there is a problem reading from the stream. * @throws NoSuchElementException if the mime-type has not been registerd. */ public static StructuredDocument newStructuredDocument(MimeMediaType mimetype, InputStream stream) throws IOException { if (!factory.loadedProperty) { factory.loadedProperty = factory.doLoadProperty(); } Instantiator instantiator = (Instantiator) factory.getInstantiator(mimetype.getMimeMediaType()); return instantiator.newInstance(mimetype, stream); }
/** * Write credential into a document. as is a mime media-type specification and provides the form * of the document which is being requested. Two standard document forms are defined. "text/text" * encodes the document in a form nice for printing out and "text/xml" which provides an XML * format. * * @param as The mime media type of the encoding format being requested. * @return the StructuredDocument which represents this credential. * @throws Exception When errors occur. */ public StructuredDocument getDocument(MimeMediaType as) throws Exception { StructuredDocument doc = StructuredDocumentFactory.newStructuredDocument(as, "jxta:Cred"); if (doc instanceof Attributable) { ((Attributable) doc).addAttribute("xmlns:jxta", "http://jxta.org"); ((Attributable) doc).addAttribute("xml:space", "preserve"); ((Attributable) doc).addAttribute("type", "AuthenticationCredential"); } Element e = doc.createElement("Method", getMethod()); doc.appendChild(e); e = doc.createElement("PeerGroupID", getPeerGroupID().toString()); doc.appendChild(e); e = doc.createElement("PeerID", getPeerID().toString()); doc.appendChild(e); if (null != identityInfo) { e = doc.createElement("IdentityInfo"); doc.appendChild(e); StructuredDocumentUtils.copyElements(doc, e, identityInfo); } return doc; }
public Document getDocument(MimeMediaType encodeAs) { StructuredTextDocument doc = null; doc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(encodeAs, paramTag); outputModules(doc, servicesTable, svcTag, encodeAs); outputModules(doc, protosTable, protoTag, encodeAs); outputModules(doc, appsTable, appTag, encodeAs); return doc; }
/** * Use this form for customized compatibility statements. Alternatively a group's compat is * accessible via group.getCompat() * * @param efmt -- something like "JDK1.4" * @param bind -- something like "V1.0 Ref Impl" * @return -- custom compatibility tag */ public static XMLDocument buildCompat(String efmt, String bind) { XMLDocument doc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, "Comp"); Element e = doc.createElement("Efmt", efmt); doc.appendChild(e); e = doc.createElement("Bind", bind); doc.appendChild(e); return doc; }
/** {@inheritDoc} */ @Override public Document getDocument(MimeMediaType asMimeType) { StructuredDocument adv = StructuredDocumentFactory.newStructuredDocument(asMimeType, getAdvertisementType()); if (adv instanceof XMLDocument) { XMLDocument xmlDoc = (XMLDocument) adv; xmlDoc.addAttribute("xmlns:jxta", "http://jxta.org"); xmlDoc.addAttribute("xml:space", "preserve"); } Element e; e = adv.createElement(typeTag, Integer.toString(getDiscoveryType())); adv.appendChild(e); int threshold = getThreshold(); if (threshold < 0) { throw new IllegalStateException("threshold must be >= 0"); } e = adv.createElement(thresholdTag, Integer.toString(threshold)); adv.appendChild(e); PeerAdvertisement peerAdv = getPeerAdvertisement(); if ((peerAdv != null)) { e = adv.createElement(peerAdvTag, peerAdv.toString()); adv.appendChild(e); } String attr = getAttr(); if ((attr != null) && (attr.length() > 0)) { e = adv.createElement(queryAttrTag, attr.trim()); adv.appendChild(e); String value = getValue(); if ((value != null) && (value.length() > 0)) { e = adv.createElement(queryValueTag, value.trim()); adv.appendChild(e); } else { if (threshold < 0) { throw new IllegalStateException("Attribute specified, but no value was specified."); } } } return adv; }
/** * Process an individual element from the document during parse. Normally, implementations will * allow the base advertisments a chance to handle the element before attempting ot handle the * element themselves. ie. * * <p> * * <p> * * <pre><code> * protected boolean handleElement(Element elem) { * <p/> * if (super.handleElement()) { * // it's been handled. * return true; * } * <p/> * <i>... handle elements here ...</i> * <p/> * // we don't know how to handle the element * return false; * } * </code></pre> * * @param elem the element to be processed. * @return true if the element was recognized, otherwise false. */ protected boolean handleElement(XMLElement elem) { String value = elem.getTextValue(); if (null == value) { return false; } value = value.trim(); if (0 == value.length()) { return false; } if (elem.getName().equals(typeTag)) { setDiscoveryType(Integer.parseInt(value)); return true; } if (elem.getName().equals(thresholdTag)) { setThreshold(Integer.parseInt(value)); return true; } if (elem.getName().equals(peerAdvTag)) { try { XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, new StringReader(value)); PeerAdvertisement adv = (PeerAdvertisement) AdvertisementFactory.newAdvertisement(asDoc); setPeerAdvertisement(adv); return true; } catch (IOException failed) { IllegalArgumentException failure = new IllegalArgumentException("Bad Peer Advertisement"); failure.initCause(failed); throw failure; } } if (elem.getName().equals(queryAttrTag)) { setAttr(value); return true; } if (elem.getName().equals(queryValueTag)) { setValue(value); return true; } // element was not handled return false; }
/** * Register an instantiator object a mime-type of documents to be constructed. * * @param mimetype the mime-type associated. * @param instantiator the instantiator that wants to be registered.. * @return boolean true if the instantiator for this mime-type is now registered. If there was * already an instantiator this mime-type then false will be returned. * @throws SecurityException there were permission problems registering the instantiator. */ public static boolean registerInstantiator(MimeMediaType mimetype, Instantiator instantiator) { boolean registered = factory.registerAssoc(mimetype.getMimeMediaType(), instantiator); if (registered) { Instantiator.ExtensionMapping[] extensions = instantiator.getSupportedFileExtensions(); for (int eachExt = 0; eachExt < extensions.length; eachExt++) { if (null != extensions[eachExt].getMimeMediaType()) { factory.extToMime.put( extensions[eachExt].getExtension(), extensions[eachExt].getMimeMediaType().getMimeMediaType()); factory.mimeToExt.put( extensions[eachExt].getMimeMediaType().getMimeMediaType(), extensions[eachExt].getExtension()); } } } return registered; }
/** * Process the Query, and generate response * * @param query the query to process */ public int processQuery(ResolverQueryMsg query) { if (!useRouteResolver) { // Route resolver disabled return ResolverService.OK; } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery starts"); } RouteQuery routeQuery = null; Reader ip = null; try { ip = new StringReader(query.getQuery()); StructuredTextDocument asDoc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, ip); routeQuery = new RouteQuery(asDoc); } catch (Throwable e) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Malformed Route query ", e); } return ResolverService.OK; } finally { try { if (null != ip) { ip.close(); ip = null; } } catch (Throwable ignored) {; } } PeerID pId = routeQuery.getDestPeerID(); if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery: looking for route to " + pId); } RouteAdvertisement srcRoute = routeQuery.getSrcRoute(); List badHops = routeQuery.getBadHops(); if (LOG.isEnabledFor(Level.DEBUG)) { if (badHops != null) { LOG.debug("processQuery: bad Hops"); for (int i = 0; i < badHops.size(); i++) { LOG.debug("processQuery: :" + ((PeerID) badHops.get(i)).toString()); } } } // if our source route is not null, then publish it if (srcRoute != null) { if (!(srcRoute.getDestPeerID()).equals(localPeerId)) { // This is not our own peer adv so we must not keep it // longer than its expiration time. try { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery: publishing sender route info " + srcRoute.getDestPeerID()); } // we only need to publish this route if // we don't know about it yet // XXX: here is where we could be more conservative and use isNormallyReachable() instead, // thus excluding // incoming messengers. if ((!router.isLocalRoute(router.pid2addr(srcRoute.getDestPeerID()))) && (!router.isRoutedRoute(router.pid2addr(srcRoute.getDestPeerID())))) { routeCM.publishRoute(srcRoute); } } catch (Exception e) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Could not publish Route Adv from query - discard", e); } return ResolverService.OK; } } } else { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("No src Route in route query - discard "); } return ResolverService.OK; } if (pId == null) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Malformed route query request, no PeerId - discard"); } return ResolverService.OK; } // We have more luck with that one because, since it is part of OUR // message, and not part of the resolver protocol, it is in OUR // format. EndpointAddress qReqAddr = router.pid2addr(pId); RouteAdvertisement route = null; // check if this peer has a route to the destination // requested boolean found = false; if (qReqAddr.equals(localPeerAddr)) { found = true; // return the route that is my local route route = router.getMyLocalRoute(); } else { // only rendezvous can respond to route requests // if not we are generating too much traffic // XXX: here is where we could be more conservative and use isNormallyReachable() instead, // thus excluding // incoming messengers. if (router.isLocalRoute(qReqAddr)) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery: peer has direct route to destination "); } // we should set the route to something :-) found = true; // this peer has a direct route to the destination // return the short route advertisement we know for this peer // (For us it is zero hop, and we advertise ourself as the routing // peer in the response. The stiching is done by whoever gets that // response). May be there are more than one hop advertised in-there... // alternate routing peers...should we leave them ? // For now, we keep the full dest, but wack the hops. route = (RouteAdvertisement) AdvertisementFactory.newAdvertisement(RouteAdvertisement.getAdvertisementType()); AccessPointAdvertisement ap = (AccessPointAdvertisement) AdvertisementFactory.newAdvertisement( AccessPointAdvertisement.getAdvertisementType()); ap.setPeerID(pId); route.setDest(ap); } else { route = router.getRoute(qReqAddr, false); if (route != null) { found = true; // check if we were given some bad hops info // and see if the found route contains // any of these bad hops. In that case, we need // to mark this route as bad for (int i = 0; i < badHops.size(); i++) { // destination is known to be bad if (router.addr2pid(qReqAddr).equals(((PeerID) badHops.get(i)))) { processBadRoute((PeerID) badHops.get(i), route); found = false; break; } if (route.containsHop((PeerID) badHops.get(i))) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug( "processQuery: peer has bad route due to " + ((PeerID) badHops.get(i)).toString()); } processBadRoute((PeerID) badHops.get(i), route); found = false; break; } } } } } if (!found) { // discard the request if we are not a rendezvous // else forward to the next peers if (!group.isRendezvous()) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("discard query forwarding as not a rendezvous"); } return ResolverService.OK; } // did not find a route, check our srdi cache // make sure we protect against out of sync // SRDI index // srdi forwarding is only involved once the Index entry has // been found and we forwarded the resolver query. Afterward a // normal walk proceeds from the initial SRDI index pointing // rdv. This is done to protect against potential loopback // entries in the SRDI cache index due to out of sync peerview // and index. if (query.getHopCount() < 2) { // check local SRDI cache to see if we have the entry // we look for 10 entries, will pickup one randomly Vector results = srdiIndex.query("route", "DstPID", pId.toString(), 10); if (results.size() > 0) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery srdiIndex lookup match :" + results.size()); } // remove any non-rdv peers to avoid sending // to a non-rdv peers and garbage collect the SRDI // index in the process Vector clean = cleanupAnyEdges(query.getSrc(), results); if (clean.size() > 0) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("found an srdi entry forwarding query to SRDI peer"); } // The purpose of incrementing the hopcount // when an SRDI index match is found (we got a // pointer to a rdv that should have the route) is to // restrict any further forwarding. The increment // count is only done when a matching SRDI index is // found. Not when the replica is selected as we // still need to forward the query. This restriction // is purposelly done to avoid too many longjumps // within a walk. query.incrementHopCount(); // Note: this forwards the query to 1 peer randomly // selected from the result srdi.forwardQuery(clean, query, 1); // tell the resolver no further action is needed. return ResolverService.OK; } } } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("did not find a route or SRDI index"); } // force a walk return ResolverService.Repropagate; } // we found a route send the response try { if (route == null) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("we should have had a route at this point"); } return ResolverService.OK; } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery: we have a route build route response" + route.display()); } RouteAdvertisement myRoute = router.getMyLocalRoute(); // make sure we initialized our local // route info as we will need it to respond. We may // not have our route if we are still // waiting for a relay connection. if (myRoute == null) { return ResolverService.OK; } RouteResponse routeResponse = new RouteResponse(); routeResponse.setDestRoute(route); routeResponse.setSrcRoute(myRoute); if (routeResponse == null) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("error creating route response"); } return ResolverService.OK; } // construct a response from the query ResolverResponseMsg res = query.makeResponse(); res.setCredential(credentialDoc); res.setResponse(routeResponse.toString()); resolver.sendResponse(query.getSrc(), res); return ResolverService.OK; } catch (Exception ee) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processQuery: error while processing query ", ee); } return ResolverService.OK; } }
/** * {@inheritDoc} * * <p>This is called by the Generic ResolverServiceImpl when processing a response to a query. */ public void processResponse(ResolverResponseMsg response) { if (!useRouteResolver) { // Route resolver disabled return; } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse got a response"); } // convert the response into a RouteResponse Reader ip = null; RouteResponse doc = null; try { ip = new StringReader(response.getResponse()); StructuredTextDocument asDoc = (StructuredTextDocument) StructuredDocumentFactory.newStructuredDocument(MimeMediaType.XMLUTF8, ip); doc = new RouteResponse(asDoc); } catch (Throwable e) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse: malformed response - discard", e); } return; } finally { try { if (null != ip) { ip.close(); ip = null; } } catch (Throwable ignored) { } } RouteAdvertisement dstRoute = doc.getDestRoute(); RouteAdvertisement srcRoute = doc.getSrcRoute(); int queryId = response.getQueryId(); if ((dstRoute == null) || (srcRoute == null)) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse: malformed response - discard."); } // Malformed response. Just discard. return; } EndpointAddress routingPeer = router.pid2addr(srcRoute.getDestPeerID()); EndpointAddress destPeer = router.pid2addr(dstRoute.getDestPeerID()); if ((routingPeer == null) || (destPeer == null)) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("processResponse: malformed PeerID in response - discard."); } // Malformed response. Just discard. return; } // check if we have a negative route response if (queryId == NACKROUTE_QUERYID) { AccessPointAdvertisement badHop = dstRoute.nextHop(router.addr2pid(routingPeer)); PeerID badPeer = null; if (badHop != null) { badPeer = badHop.getPeerID(); } else { // the bad hop is the final destination badPeer = dstRoute.getDestPeerID(); } processBadRoute(badPeer, dstRoute); return; } // This is not our own peer adv, so we must not keep it // for more than its expiration time. // we only need to publish this route if // we don't know about it yet // XXX: here is where we could be more conservative and use isNormallyReachable() instead, thus // excluding // incoming messengers. if ((!router.isLocalRoute(router.pid2addr(srcRoute.getDestPeerID()))) && (!router.isRoutedRoute(router.pid2addr(srcRoute.getDestPeerID())))) { router.updateRouteAdv(srcRoute); } if (destPeer.equals(routingPeer)) { // The dest peer itself managed to respond to us. That means we // learned the route from the reverseRoute in the message // itself. So, there's nothing we need to do. if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("learn route directly from the destination"); } } else { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("learn route:" + routingPeer); } try { // build the candidate route using the // route response from the respondant peer RouteAdvertisement candidateRoute = RouteAdvertisement.newRoute( router.addr2pid(destPeer), router.addr2pid(routingPeer), (Vector) dstRoute.getVectorHops().clone()); // cleanup the candidate route from any loop and remove the local peer extra // cycle RouteAdvertisement.cleanupLoop(candidateRoute, (PeerID) localPeerId); // Is there anything left in that route (or did the respondant // believe that we are the last hop on the route - which // obviously we are not. if (candidateRoute.size() == 0) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response outdated: NACK responder"); } generateNACKRoute( router.addr2pid(routingPeer), router.addr2pid(destPeer), dstRoute.getVectorHops()); return; } // get the address of the first hop in the route to verify that // we have a route (direct or long) to the first hop, so the route // is valid EndpointAddress candidateRouter = router.pid2addr(candidateRoute.getFirstHop().getPeerID()); // check that we have a direct connection to the first hop if (router.ensureLocalRoute(candidateRouter, null) == null) { // If we do not have a direct route to the candidate router check // for a long route in that case stich the route RouteAdvertisement routeToRouter = router.getRoute(candidateRouter, false); if (routeToRouter == null) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response useless: no route to next router hop"); } return; } // stich the route removing any loops and localPeer cycle if (RouteAdvertisement.stichRoute(candidateRoute, routeToRouter, (PeerID) localPeerId)) { router.setRoute(candidateRoute, false); } else { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response error stiching route response"); } return; } } else { // we have a direct connection with the first hop of the candidate route // set the new route, which starts with the peer that replied to us. router.setRoute(candidateRoute, false); } } catch (Exception ex) { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Route response exception when building response route" + ex); LOG.debug(" bad dstRoute: " + dstRoute.display()); } } if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("finish process route response successfully"); } } }
/** * process an SRDI message request * * @param message SRDI resolver message */ public boolean processSrdi(ResolverSrdiMsg message) { String value; SrdiMessage srdiMsg; try { if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug("Received a SRDI messsage in group" + group.getPeerGroupName()); } XMLDocument asDoc = (XMLDocument) StructuredDocumentFactory.newStructuredDocument( MimeMediaType.XMLUTF8, new StringReader(message.getPayload())); srdiMsg = new SrdiMessageImpl(asDoc); } catch (Exception e) { // we don't understand this msg, let's skip it if (LOG.isEnabledFor(Level.WARN)) { LOG.warn("corrupted SRDI message", e); } return false; } PeerID pid = srdiMsg.getPeerID(); // filter messages that contain messages // about the local peer, so we don't enter // self-reference if (pid.equals(localPeerId)) { return false; } Iterator eachEntry = srdiMsg.getEntries().iterator(); while (eachEntry.hasNext()) { SrdiMessage.Entry entry = (SrdiMessage.Entry) eachEntry.next(); // drop any information about ourself if (entry.key.equals(localPeerId.toString())) { continue; } value = entry.value; if (value == null) { value = ""; } // Expiration of entries is taken care of by SrdiIdex, so we always add // FIXME hamada 03142003 // All routes are added under the secondary key 'DstPID', it would be more correct to // Specify it in the message, but since versioning is not yet supported the following is // acceptable, since it is localized srdiIndex.add(srdiMsg.getPrimaryKey(), "DstPID", entry.key, pid, entry.expiration); if (LOG.isEnabledFor(Level.DEBUG)) { LOG.debug( "Primary Key [" + srdiMsg.getPrimaryKey() + "] key [DstPID]" + " value [" + entry.key + "] exp [" + entry.expiration + "]"); } } return true; }