264 lines
9.2 KiB
Java
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();
|
|
}
|
|
}
|
|
} |