Files
tilman.de/www/uni/ws04/netzprogrammierung/SiteSize.java
T
2011-10-26 10:11:42 +02:00

264 lines
9.2 KiB
Java

//Gruppe 01 (Übung 4)
//Aufgabe 4-3
package uebung04.aufgabe03;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTML.Tag;
import javax.swing.text.html.HTMLEditorKit.ParserCallback;
import javax.swing.text.html.parser.ParserDelegator;
/**
* Sucht in einer HTML-Ressource nach eingebetten Objekten und summiert die Dateigrößen auf,
* wobei mehrfach verlinkte Objekte nur einmal gezählt werden.
* Bei Framesets werden sämtliche Frames ausgewertet, in mehreren Frames dargestellte Seiten
* werden nur einfach gezählt.
*
* @author Tilman Walther
* @version 2.1
*/
public class SiteSize extends ParserCallback {
private URL url; // die URL der HTML-Ressource
private URLConnection connection; // Verbindung zur HTML-Ressource
private HashSet objects = null; // speichert URLs der bereits gezählten Objekten
private long size = 0; // die Größe aller gezählten Objekte
private ParserDelegator parser = new ParserDelegator(); // parst die Ressource und ruft handleSimpleTag() auf
/**
* Parses the resource behind the given URL and measures the size.
* If the URL points to a non-HTML resource the size will be zero.
* @param url the URL for the resource to parse
* @return the size of the website including all embedded objects
* @throws IOException if an I/O error occurs
*/
public long getSize(URL url) throws IOException {
/* Für Testzwecke: Durchleitungsproxy einstellen /
java.util.Properties props = System.getProperties();
props.put("proxySet", "true");
props.put("proxyHost", "127.0.0.1");
props.put("proxyPort", "10000");
/* --------------------------------------------- */
System.out.println("\nparsing "+url);
this.url = url;
connection = url.openConnection();
// Daten vom Server im "identity"-Format anfordern
connection.addRequestProperty("Accept-Encoding", "identity");
// TODO für Testzwecke:
//connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.5.6 (KHTML, like Gecko) Safari/125.12");
connection.connect();
//System.out.println("Transfer-Encoding: "+connection.getHeaderField("transfer-encoding")+"\n");
// falls objects nicht bereits durch den privaten Konstruktor
// inititalisiert wurde, neues HashSet erzeugen
if (objects == null) objects = new HashSet();
// auf HTML-Inhalt prüfen
if (connection.getContentType().startsWith("text/html")) {
// Größe der Seite zur Gesamtgröße addieren
addSize(url);
// eingebettete Objekte mit Parser finden/addieren
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
parser.parse(br, this, true);
}
// Gesamtgröße zurückgeben
return size;
}
/**
* This private method is used for recursive processing of framesets.
* In order not to count linked objects twice, the HashSet 'objects' is passed.
* @param url the URL for the actual frame
* @param objects the HashSet containing all objects that have already been counted
* @return the size if the subframe
* @throws IOException if an I/O error occurs
*/
private long getSize(URL url, HashSet objects) throws IOException {
this.objects = objects;
return getSize(url);
}
/**
* Overrides javax.swing.text.html.HTMLEditorKit.ParserCallback.handleSimpleTag() which is called by the ParserDelegator
* @see javax.swing.text.html.HTMLEditorKit.ParserCallback#handleSimpleTag(javax.swing.text.html.HTML.Tag, javax.swing.text.MutableAttributeSet, int)
*/
public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
String objLink = null;
try {
if (t == HTML.Tag.FRAME) {
// leider trifft man öfter auf dummy-frames (Dreamweaver!), deswegen
// fehlt ab und zu die Quelle
if (a.getAttribute(HTML.Attribute.SRC) != null) {
// absuluten Pfad zur Ressource nachvollziehen, um mehrfache Zählung zu vermeiden
URL frameUrl = generateURL(a.getAttribute(HTML.Attribute.SRC).toString());
// Frame von neuem SiteSize-Objekt parsen lassen
SiteSize frameSize = new SiteSize();
size += frameSize.getSize(frameUrl, objects);
}
} else {
if (t == HTML.Tag.APPLET) {
// Applets können direkt via CODE-Attribut oder als Archiv verlinkt sein
if (a.getAttribute(HTML.Attribute.ARCHIVE) != null) {
objLink = a.getAttribute(HTML.Attribute.ARCHIVE).toString();
} else {
objLink = a.getAttribute(HTML.Attribute.CODE).toString();
}
} else if (t == HTML.Tag.IMG) {
objLink = a.getAttribute(HTML.Attribute.SRC).toString();
} else if (t == HTML.Tag.OBJECT) {
objLink = a.getAttribute(HTML.Attribute.DATA).toString();
} else if (t == HTML.Tag.LINK) {
objLink = a.getAttribute(HTML.Attribute.HREF).toString();
}
if (objLink != null) {
try {
// absuluten Pfad zur Ressource nachvollziehen, um mehrfache Zählung zu vermeiden
addSize(generateURL(objLink));
} catch (MalformedURLException mue) {
System.out.println("MalformedURLException on position " + pos + ": '" + objLink + "'");
}
}
}
} catch (IOException ioe) {
System.out.println("IOException (" + pos + "): Could not connect to linked object. ("+objLink+")");
}
}
/**
* Overrides javax.swing.text.html.HTMLEditorKit.ParserCallback.handleStartTag() which is called by the ParserDelegator.
* @see javax.swing.text.html.HTMLEditorKit.ParserCallback#handleStartTag(javax.swing.text.html.HTML.Tag, javax.swing.text.MutableAttributeSet, int)
*/
public void handleStartTag(Tag t, MutableAttributeSet a, int pos) {
// Da APPLET- und OBJECT-Tags auch als StartTags vorkommen können, wird das der Aufruf
// in diesem Fall an handleSimpleTag() weitergegeben
if ((t == HTML.Tag.APPLET) || (t == HTML.Tag.OBJECT)) handleSimpleTag(t, a, pos);
}
/**
* Adds the size of the resource that the given URLConnection points to if it has not already been counted
* @param connection an URLConnection to a resource
* @throws IOException if an I/O error occurs
*/
private void addSize(URL url) throws IOException {
URLConnection resConn = url.openConnection();
// TODO für Testzwecke:
//resConn.addRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; de-DE; rv:1.7) Gecko/20040803 Firefox/0.9.3");
resConn.connect();
String resUrlStr = url.toString();
if (!objects.contains(resUrlStr)) {
objects.add(resUrlStr);
int resLength = resConn.getContentLength();
if (resLength >= 0) {
size += resLength;
}
else {
// da der Content-Length Header nicht übermittelt wurde, muss zur
// Messung die Ressource übertragen werden
int bytesRead;
byte[] buffer = new byte[1024];
BufferedInputStream input = new BufferedInputStream(resConn.getInputStream());
resLength = 0;
while ((bytesRead = input.read(buffer)) >= 0) {
resLength += bytesRead;
}
size += resLength;
}
System.out.println("added '" + resUrlStr + "' (" + resLength + " bytes)");
}
}
/**
* Generates the URL for a (relative) link extracted from a tag attribute
* @param link a resource link from a tag attribute
* @return the URL to the resource
* @throws MalformedURLException
*/
// TODO wahrscheinlich lässt sich diese Methode (zumindest teilw.) durch URI.relativize() ersetzen
private URL generateURL(String link) throws MalformedURLException {
if (link.startsWith("//")) link = "http:" + link;
String resUrlStr = null;
if (link.indexOf("://") > 0) {
resUrlStr = new String(link);
} else if (link.startsWith("/")) {
resUrlStr = new String(url.getProtocol() + "://" + url.getAuthority() + link);
} else {
String path = url.getPath();
if (path.length() > 0) path = path.substring(0, path.lastIndexOf("/"));
resUrlStr= new String(url.getProtocol() + "://" + url.getAuthority() + path + "/" + link);
}
int i, j;
while ( ((i = resUrlStr.indexOf("../")) > -1) && ((j = resUrlStr.indexOf("/", i+3)) > -1) ){
resUrlStr = resUrlStr.substring(0,i) + resUrlStr.substring(j+1);
}
//new URL(URLEncoder.encode(resUrlStr, "UTF-8"));
return new URL(resUrlStr);
}
public static void main(String[] args) {
try {
String urlString;
if (args.length == 0) {
// URL von der Kommandozeile lesen
BufferedReader din = new BufferedReader(new InputStreamReader(System.in));
System.out.print("URL: ");
urlString = din.readLine();
} else {
urlString = args[0];
}
// URL erzeugen
URL url = new URL(urlString);
// SiteSize-Objekt erzeugen
SiteSize siteSize = new SiteSize();
// Brutto-Größe messen und ausgeben
System.out.println("\nSize of content: " + siteSize.getSize(url) + " bytes");
} catch (Exception e) {
e.printStackTrace();
}
}
}