<body>

Sitios web relacionados: PingBlog | Fotos

sábado, enero 07, 2006

Echando código: Borrón y cuenta nueva (II)



En un articulo anterior, les mostraba como bajarme los datos de un par de sitios de Internet, los procesaba y luego los dejaba listos para ser cargados en una base de datos. El problema es que mi proveedor de hospedaje decidió que el soporte de Threads para Perl es experimental y no lo soportan.

Esta vez decidí organizar mis ideas un poco mejor, y al final terminé con los siguientes casos de uso:



Pada muy formal, pero al menos podré recordar que estaba tratando de hacer cuando mire el código de nuevo en unos cuantos meses ;)

Que machete, Dios mio. ¿Qué hacer?. Bueno, en otra conversación que tuve con ellos al menos soportan Java, así que vamos a ver que tal me va. Como soy perezoso y quiero hacer las cosas ŕapido esta vez, en vez de lanzarme con la clase java.net.URL voy a utilizar el cliente de Apache 'HttpClient'. Bueno, una vez que me lo bajé me pusé a echar código y al final terminé con un pequeño programa que hacia lo que yo queria.

La idea aquí es la siguiente: Una clase actua como controlador (GeoDataFinder) y esta es quien usa al cliente de Apache con un par de hebras (Threads) para bajarnos los archivos de datos. Luego la responsabilidad de como procesar los archivos es delegada a un par de clases en Java las cuales implementan el contrato (interface) CVSParser.

   1:package com.kodegeek.blog.batch.geo;
2:
3:import org.apache.commons.httpclient.*;
4:import org.apache.commons.httpclient.methods.*;
5:
6:import java.io.*;
7:
8:import java.util.ResourceBundle;
9:
10:/**
11: * This program will download IP to Geographic location data files and will
12: * process them so they can be loaded into a database.
13: *
14: * @author josevnz@kodegek.com
15: * @version 1.0 - 12/03/2005
16: *
17: */
18:public final class GeoDataFinder {
19:
20: Thread [] _threads = new Thread[2];
21:
22: public static ResourceBundle BUNDLE;
23:
24: {
25: BUNDLE = ResourceBundle.getBundle(GeoDataFinder.class.getName());
26: }
27:
28: public static final int MAX_BUFFER_SIZE = 81920;
29:
30: // Inner class that will take care of the downloads
31: final public class Downloader implements Runnable {
32:
33: private CSVParser _parser;
34: private String _url;
35: private HttpClient _client;
36:
37: /**
38: * Parametric constructor
39: * @param conManager Conection manager
40: * @param URL URL to download
41: * @param parser Parse to use to process the downloaded file
42: * Parametric constructor
43: */
44: public Downloader(MultiThreadedHttpConnectionManager
conManager, String URL, CSVParser parser) {
45: if (conManager == null) {
46: throw new NullPointerException(
47: BUNDLE.getString("
com.kodegeek.blog.batch.geo.GeoDataFinder.error.missingProp
") +
48: ": conManager");
49: }
50:
51: if (URL == null) {
52: throw new NullPointerException(
53: BUNDLE.getString(
"
com.kodegeek.blog.batch.geo.GeoDataFinder.error.missingProp") +
54: ": URL");
55: }
56:
57: _url = URL;
58: if (parser == null) {
59: throw new NullPointerException(
60: BUNDLE.getString(
"
com.kodegeek.blog.batch.geo.GeoDataFinder.error.missingProp") +
61: ": parser");
62: }
63:
64: _parser = parser;
65: _client = new HttpClient(conManager);
66: }
67:
68: /**
69: * Download and parse the required files
70: * @see java.lang.Runnable#run()
71: */
72: public void run() {
73: GetMethod method = null;
74: OutputStream out = null;
75: InputStream in = null;
76: byte [] buffer = new byte[MAX_BUFFER_SIZE];
77:
78: try {
79: method = new GetMethod(_url);
80: _client.executeMethod(method);
81: out =
82: new FileOutputStream(
_parser.getSourceFilename());
83: in = method.getResponseBodyAsStream();
84: int readBytes = 0;
85: while( ( readBytes = in.read(buffer) ) != -1 ) {
86: out.write(buffer, 0, readBytes);
87: }
88: out.flush();
89: // Parse the file
90: _parser.parseToFile();
91: } catch (IOException ioExp) {
92: throw new RuntimeException(ioExp);
93: } finally {
94: if (out != null) {
95: try {
96: out.close();
97: } catch (IOException exp) {
98: throw new RuntimeException(exp);
99: }
100: }
101:
102: if (in != null) {
103: try {
104: in.close();
105: } catch (IOException exp) {
106: throw new RuntimeException(exp);
107: }
108: }
109:
110: if (method != null) {
111: method.releaseConnection();
112: }
113:
114: buffer = null;
115: }
116: }
117: }
118:
119: /**
120: * Default constructor
121: * @since 0.1
122: */
123: private GeoDataFinder() throws Exception {
124: super();
125:
126: MultiThreadedHttpConnectionManager connectionManager =
127: new MultiThreadedHttpConnectionManager();
128:
129: CSVParser ASparser = new
130: CSVAsParser(System.getProperty(
"AsSourceFile"), System.getProperty("AsParsedFile"));
131:
132: CSVParser Geoparser = new
133: CSVGeoParser(System.getProperty(
"
GeoSourceFile"), System.getProperty("GeoParsedFile"));
134:
135: Downloader ASDownloader =
136: new Downloader(connectionManager,
System.getProperty("AsUrl"), ASparser);
137:
138: Downloader GeoDownloader =
139: new Downloader(connectionManager,
System.getProperty("GeoUrl"), Geoparser);
140:
141: _threads[0] = new Thread(ASDownloader);
//
Get the AS file and parse it
142: _threads[1] = new Thread(GeoDownloader);
//
Get the Geo file and parse it
143:
144: // Start the work
145: for (int i= 0; i < _threads.length; i++) {
146: _threads[i].start();
147: }
148:
149: // Wait for all to finish
150: for (int i= 0; i < _threads.length; i++) {
151: _threads[i].join();
152: }
153:
154: }
155:
156: /**
157: * @param args
158: * @throws Exception
159: * @since 0.1
160: */
161: public static void main(String[] args) throws Exception {
162: GeoDataFinder instance = null;
163: /*
164: * Define the basic loging level
165: */
166: if (System.getProperty("
org.apache.commons.logging.Log
") == null)
167: System.setProperty("
org.apache.commons.logging.Log
", "org.apache.commons.logging.impl.SimpleLog");
168: if (System.getProperty("
org.apache.commons.logging.simplelog.showdatetime
") == null)
169: System.setProperty("
org.apache.commons.logging.simplelog.showdatetime
", "true");
170: if (System.getProperty("
org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient
") == null)
171: System.setProperty("
org.apache.commons.logging.simplelog.log.org.apache.commons.httpclient
", "info");
172:
173: try {
174: instance = new GeoDataFinder();
175: } catch (Exception exp) {
176: throw exp;
177: } finally {
178: instance.cleanup();
179: }
180: }
181:
182: /**
183: * Finall resource cleanup
184: */
185: private void cleanup() {
186:
187: for (int i= 0; i < _threads.length; i++) {
188: _threads[i] = null;
189: }
190: }
191:
192: /**
193: * Last chance resource cleanup
194: */
195: public void destroy() {
196: cleanup();
197: }
198:}
Y este es el contrato que debe ser implementado por cada uno de los "parsers":
   1:package com.kodegeek.blog.batch.geo;
2:
3:import java.io.IOException;
4:
5:
6:/**
7: * Contract to be followed for any class that implements a CSV parser
8: * @author josevnz@kodegeek.com
9: * @version 1.0 - 12/03/2005
10: */
11:public interface CSVParser {
12:
13: /**
14: * Parse the original file and write the results somewhere else.
15: * @throws IOException
16: */
17: public void parseToFile() throws IOException;
18:
19: /**
20: * Get the name of the source file
21: * @return String
22: */
23: public String getSourceFilename();
24:
25: /**
26: * Get the name of the destination file
27: * @return String
28: */
29: public String getDestFilename();
30:
31:}
Aún el código no está completo, pero la idea va en camino. Una vez que tenga estos datos entonces si podré concentrarme en lo que realmente quiero hacer con ellos.

Por cierto, el programa que utilicé para hacer los diagramas en UML es el super conocido ArgoUML. Muy bueno, denle una probadita si aún no han tenido la oportunidad.

Buscar en Technorati:

0 Comentarios:

Publicar un comentario en la entrada

Enlaces a este articulo:

Crear un vínculo

<< Regresar