Java tutorial
/* * PHEX - The pure-java Gnutella-servent. * Copyright (C) 2001 - 2005 Phex Development Group * * 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 * * --- CVS Information --- * $Id: AlternateLocationContainer.java,v 1.19 2005/11/03 16:33:45 gregork Exp $ */ package phex.common; import java.util.*; import javax.xml.bind.JAXBException; import org.apache.commons.collections.SequencedHashMap; import phex.common.address.DestAddress; import phex.http.HTTPHeader; import phex.utils.Logger; import phex.utils.NLogger; import phex.utils.NLoggerNames; import phex.xml.ObjectFactory; import phex.xml.XJBAlternateLocation; /** * A AlternateLocationContainer that helps holder to add, sort and access * AlternateLocations. * * @author Gregor Koukkoullis */ public class AlternateLocationContainer { public static final int MAX_ALT_LOC_COUNT = 100; // Dummy value to associate with an Object in the backing Map private static final Object PRESENT = new Object(); /** * The urn each alternate location must match to be accepted. */ private URN urn; /** * The map of AlternateLocations. It is lazy initialized on first use and * sorted by timestamp.<br> * We are using a SequencedHashMap that allows use to remove the alt loc * which has not been seen (put) into the map for the longest time. */ private SequencedHashMap altLocationMap; public AlternateLocationContainer(URN urn) { if (urn == null) { throw new NullPointerException("URN must be provided"); } this.urn = urn; } public void addContainer(AlternateLocationContainer cont) { if (cont.urn == null || !cont.urn.equals(urn)) { // dont add container with wrong or not existing sha1. // This is a implementation error. throw new IllegalArgumentException("Trying to add container with not matching urns"); } // this check prevents a NullPointerException during putAll(); if (cont.altLocationMap == null) {// nothing to add.. return; } initMap(); synchronized (cont.altLocationMap) { Iterator iterator = cont.altLocationMap.keySet().iterator(); AlternateLocation tempAltLoc; while (iterator.hasNext()) { tempAltLoc = (AlternateLocation) iterator.next(); addAlternateLocation(tempAltLoc); } } } public void addAlternateLocation(AlternateLocation altLoc) { URN altLocURN = altLoc.getURN(); if (altLocURN == null || !altLocURN.equals(urn)) {// dont add alt location with wrong or not existing sha1 Logger.logMessage(Logger.WARNING, Logger.DOWNLOAD, "Cant add alt-location with not matching URN to container "); return; } initMap(); synchronized (altLocationMap) { // thanks to AlternateLocation hashCode implementation the map ensures // that each alt loc is only once present. The put operation of a // duplicate alt loc is required here to update the SequencedHashMap // internal order of elements. This ensures that alt loc not seen // for a long time get removed from the map. altLocationMap.put(altLoc, PRESENT); // make sure we have not more then 100 alt locations. if (altLocationMap.size() > MAX_ALT_LOC_COUNT) {// drop last element Object firstKey = altLocationMap.getFirstKey(); altLocationMap.remove(firstKey); } } } public void removeAlternateLocation(AlternateLocation altLoc) { URN altLocURN = altLoc.getURN(); if (altLocURN == null || !altLocURN.equals(urn)) {// dont add alt location with wrong or not existing sha1 Logger.logMessage(Logger.WARNING, Logger.DOWNLOAD, "Cant remove alt-location with not matching URN to container "); return; } initMap(); synchronized (altLocationMap) { altLocationMap.remove(altLoc); } } public void addFromUriResHTTPHeaders(HTTPHeader[] headers) { List altLocList = parseUriResAltLocFromHTTPHeaders(headers); Iterator iterator = altLocList.iterator(); while (iterator.hasNext()) { addAlternateLocation((AlternateLocation) iterator.next()); } } public void addFromCompactIpHTTPHeaders(HTTPHeader[] headers, URN urn) { List altLocList = parseCompactIpAltLocFromHTTPHeaders(headers, urn); Iterator iterator = altLocList.iterator(); while (iterator.hasNext()) { addAlternateLocation((AlternateLocation) iterator.next()); } } /** * Returns a HTTPHeader array for this host address. This will include all * alternate locations except the one that equals the host address and the * one contained in the sendAltLocList. The newly send alt locs are added * to the sendAltLocList inside this call. * * @param the name of the http header to generate, use X-ALT or X-NAlt. * @param hostAddress the host address that gets the alternate locations. * @param sendAltLocList a list of already send alt locs. * @return a HTTPHeader array for this host address */ public HTTPHeader getAltLocHTTPHeaderForAddress(String headerName, DestAddress hostAddress, Set sendAltLocSet) { if (isEmpty()) { return null; } int count = 0; StringBuffer headerValue = new StringBuffer(); synchronized (altLocationMap) { Iterator iterator = altLocationMap.keySet().iterator(); while (iterator.hasNext()) { AlternateLocation altLoc = (AlternateLocation) iterator.next(); // filter out alt locations to given host address.. if (hostAddress.getHostName().equals(altLoc.getHostAddress().getHostName())) { continue; } // filter out already send alt locs... if (sendAltLocSet.contains(altLoc)) { continue; } if (count > 0) { headerValue.append(","); } headerValue.append(altLoc.getHTTPString()); sendAltLocSet.add(altLoc); count++; if (count == 10) { break; } } } if (headerValue.length() > 0) { HTTPHeader altLocHeader = new HTTPHeader(headerName, headerValue.toString()); return altLocHeader; } else { return null; } } /** * Returns the number of alternate locations in the container. * @return the number of alternate locations in the container. */ public synchronized int getSize() { if (altLocationMap == null) { return 0; } else { return altLocationMap.size(); } } /** * Indicates whether the container is empty or not. * @return <code>true</code> if the container is empty, <code>false</code> * otherwise. */ public synchronized boolean isEmpty() { if (altLocationMap == null) { return true; } else { return altLocationMap.isEmpty(); } } public synchronized void createXJBAlternateLocationList(List list) throws JAXBException { if (altLocationMap == null) { return; } Iterator iterator = altLocationMap.keySet().iterator(); ObjectFactory objFactory = new ObjectFactory(); while (iterator.hasNext()) { AlternateLocation altLoc = (AlternateLocation) iterator.next(); XJBAlternateLocation xjbAltLoc = objFactory.createXJBAlternateLocation(); xjbAltLoc.setHostAddress(altLoc.getHostAddress().getFullHostName()); xjbAltLoc.setURN(altLoc.getURN().getAsString()); list.add(xjbAltLoc); } } /** * Returns a string representation of the object. * @return a string representation of the object. */ public synchronized String toString() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("Alt-Locations(SHA1: "); stringBuffer.append(urn.getAsString()); stringBuffer.append(")=[ "); if (altLocationMap != null) { Iterator iterator = altLocationMap.keySet().iterator(); AlternateLocation altLoc; while (iterator.hasNext()) { altLoc = (AlternateLocation) iterator.next(); stringBuffer.append(altLoc.toString()); stringBuffer.append(", "); } } stringBuffer.append(" ]"); return stringBuffer.toString(); } private void initMap() { if (altLocationMap == null) { altLocationMap = new SequencedHashMap(); } } /** * Parses AlternateLocations from the values of the given http headers and * returns a List containing the results. * @param headers HTTPHeaderGroup to parse the AlternateLocations from * @return List containing all AlternateLocations found. */ public static List parseUriResAltLocFromHTTPHeaders(HTTPHeader[] headers) { if (headers.length == 0) { return Collections.EMPTY_LIST; } List altLocList = new ArrayList(); StringTokenizer tokenizer; for (int i = 0; i < headers.length; i++) { HTTPHeader header = headers[i]; tokenizer = new StringTokenizer(header.getValue(), ","); while (tokenizer.hasMoreTokens()) { try { String altLocationStr = tokenizer.nextToken().trim(); AlternateLocation altLocation = AlternateLocation.parseUriResAltLoc(altLocationStr); if (altLocation == null) { continue; } altLocList.add(altLocation); } // TODO filter this out // this is currently just to make sure we have no untested error cases. // and the download will not fail because of this. catch (Exception exp) { NLogger.error(NLoggerNames.GLOBAL, exp, exp); } } } return altLocList; } /** * Parses AlternateLocations from the values of the given http headers and * returns a List containing the results. * @param headers HTTPHeaderGroup to parse the AlternateLocations from * @return List containing all AlternateLocations found. */ public static List parseCompactIpAltLocFromHTTPHeaders(HTTPHeader[] headers, URN urn) { if (headers.length == 0) { return Collections.EMPTY_LIST; } List altLocList = new ArrayList(); StringTokenizer tokenizer; for (int i = 0; i < headers.length; i++) { HTTPHeader header = headers[i]; tokenizer = new StringTokenizer(header.getValue(), ","); while (tokenizer.hasMoreTokens()) { try { String altLocationStr = tokenizer.nextToken().trim(); AlternateLocation altLocation = AlternateLocation.parseCompactIpAltLoc(altLocationStr, urn); if (altLocation == null) { continue; } altLocList.add(altLocation); } // TODO filter this out // this is currently just to make sure we have no untested error cases. // and the download will not fail because of this. catch (Exception exp) { NLogger.error(NLoggerNames.GLOBAL, exp, exp); } } } return altLocList; } }