package net.sf.jpluck.conversion;
import java.awt.Window;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Logger;
import net.sf.jpluck.ClientConfiguration;
import net.sf.jpluck.http.CookieStore;
import net.sf.jpluck.http.HttpCache;
import net.sf.jpluck.http.HttpClient;
import net.sf.jpluck.jxl.Site;
import net.sf.jpluck.palm.Database;
import net.sf.jpluck.palm.RecordListener;
import net.sf.jpluck.plucker.Document;
import net.sf.jpluck.spider.Spider;
import net.sf.jpluck.spider.SpiderListener;
import net.sf.jpluck.util.LogFormatter;
import net.sf.jpluck.util.LogUtil;
import net.sf.jpluck.util.TemporaryFile;
public class Conversion implements Runnable {
// TODO: Improve this. A flaw with this flag is that it does not support multiple simultaneous conversions.
public static boolean conversionActive = false;
private CookieStore cookieStore;
private Destination destination;
private HttpCache httpCache;
private List conversionListenerList = new ArrayList();
private List recordListenerList = new ArrayList();
private List spiderListenerList = new ArrayList();
private Logger logger = Logger.getLogger("conversion");
private Spider spider;
private Window window;
private net.sf.jpluck.jxl.Document[] jxlDocuments;
private volatile boolean running;
private int failCount;
private int httpTimeout;
private int maxConnections;
public Conversion(net.sf.jpluck.jxl.Document[] jxlDocuments, Destination destination, HttpCache httpCache,
CookieStore cookieStore, int maxConnections, int timeout) {
if (destination==null) {
throw new IllegalStateException("No destination configured.");
}
this.jxlDocuments = jxlDocuments;
this.httpCache = httpCache;
this.destination = destination;
this.cookieStore = cookieStore;
this.maxConnections = maxConnections;
this.httpTimeout = timeout;
}
public Conversion(net.sf.jpluck.jxl.Document[] jxlDocuments, Destination destination) {
this(jxlDocuments, destination, ClientConfiguration.getDefault().getHttpCache(),
ClientConfiguration.getDefault().getCookieStore(), ClientConfiguration.getDefault().getMaxConnections(),
ClientConfiguration.getDefault().getTimeout());
}
public Conversion(net.sf.jpluck.jxl.Document[] jxlDocuments) {
this(jxlDocuments, ClientConfiguration.getDefault().getDestination(), ClientConfiguration.getDefault().getHttpCache(),
ClientConfiguration.getDefault().getCookieStore(), ClientConfiguration.getDefault().getMaxConnections(),
ClientConfiguration.getDefault().getTimeout());
}
public static boolean isConversionActive() {
return conversionActive;
}
public Destination getDestination() {
return destination;
}
public net.sf.jpluck.jxl.Document[] getDocuments() {
net.sf.jpluck.jxl.Document[] newJxlDocuments = new net.sf.jpluck.jxl.Document[jxlDocuments.length];
System.arraycopy(jxlDocuments, 0, newJxlDocuments, 0, jxlDocuments.length);
return newJxlDocuments;
}
public int getFailCount() {
return failCount;
}
public boolean isRunning() {
return running;
}
public void setWindow(Window window) {
this.window = window;
}
public void addConversionListener(ConversionListener listener) {
if (!conversionListenerList.contains(listener)) {
conversionListenerList.add(listener);
}
}
public void addRecordListener(RecordListener listener) {
if (!recordListenerList.contains(listener)) {
recordListenerList.add(listener);
}
}
public void addSpiderListener(SpiderListener listener) {
if (!spiderListenerList.contains(listener)) {
spiderListenerList.add(listener);
}
}
public synchronized void cancel() {
if (running) {
running = false;
if (spider != null) {
spider.cancel();
}
TemporaryFile.clean();
closeHttpCache();
fireConversionFinished();
}
}
public void removeConversionListener(ConversionListener listener) {
if (conversionListenerList.contains(listener)) {
conversionListenerList.remove(listener);
}
}
public void removeRecordListener(RecordListener listener) {
if (recordListenerList.contains(listener)) {
recordListenerList.remove(listener);
}
}
public void removeSpiderListener(SpiderListener listener) {
if (spiderListenerList.contains(listener)) {
spiderListenerList.remove(listener);
}
}
public void run() {
running = true;
conversionActive = true;
ClientConfiguration conf = ClientConfiguration.getDefault();
if (conf.isUseProxy()) {
System.setProperty("http.proxyHost", conf.getProxyHost());
System.setProperty("http.proxyPort", String.valueOf(conf.getProxyPort()));
if (conf.getProxyUser().length() > 0) {
System.setProperty(HttpClient.PROXY_USER_KEY, conf.getProxyUser());
System.setProperty(HttpClient.PROXY_PASSWORD_KEY, conf.getProxyPassword());
}
}
LogUtil logUtil = new LogUtil(LogUtil.DEFAULT_LOGGER_NAMES);
logUtil.setLevel(conf.getLogLevel());
logUtil.setUseParentHandler(false);
String logFile = conf.getLogFile();
FileHandler fileHandler = null;
if (conf.isLogEnabled() && logFile.length() > 0) {
try {
fileHandler = new FileHandler(logFile, conf.getMaxLogSize() * 1024, 1, true);
fileHandler.setFormatter(new LogFormatter());
logUtil.addHandler(fileHandler);
} catch (IOException e) {
logger.warning("Could not create log file " + e.getMessage());
}
}
for (int i = 0; (i < jxlDocuments.length) && running; i++) {
try {
net.sf.jpluck.jxl.Document jxlDocument = jxlDocuments[i];
if (jxlDocument.getUserAgent() != null) {
System.setProperty("http.agent", jxlDocument.getUserAgent());
} else {
System.setProperty("http.agent", conf.getUserAgent());
}
String s = "Starting conversion: " + jxlDocument.getName();
if (jxlDocument.getJXL() != null) {
File f = jxlDocument.getJXL().getFile();
if (f != null) {
s += " (" + f.getAbsolutePath() + ")";
}
logger.info(s);
}
jxlDocument.init();
fireConversionStarted(jxlDocument, i + 1, jxlDocuments.length);
String name = jxlDocument.getName();
if (jxlDocument.isRemoveAccents()) {
name = Database.convertToDatabaseName(name);
}
Document document = new Document(name, ClientConfiguration.getDefault().getCompression());
Date date = jxlDocument.getDate();
if (date != null) {
document.setCreationDate(date);
document.setModificationDate(date);
}
spider = new Spider(document, jxlDocument, httpCache, cookieStore, maxConnections,
Spider.DEFAULT_MAX_PARSE_THREADS, httpTimeout);
try {
for (Iterator iterator = spiderListenerList.iterator(); iterator.hasNext();) {
SpiderListener spiderListener = (SpiderListener) iterator.next();
spider.addSpiderListener(spiderListener);
}
if (!running) {
break;
}
spider.run();
} finally {
for (Iterator iterator = spiderListenerList.iterator(); iterator.hasNext();) {
SpiderListener spiderListener = (SpiderListener) iterator.next();
spider.removeSpiderListener(spiderListener);
}
}
boolean success = false;
if (!running) {
break;
}
String uri = jxlDocument.getStartingURI().toString();
if (document.contains(uri)) {
try {
document.setHome(uri);
document.setOutputEncoding(jxlDocument.getOutputEncoding());
document.setIncludeImageAltText(jxlDocument.isIncludeAltText());
document.setCategories(jxlDocument.getCategories());
document.setDefaultLinkColor(jxlDocument.getLinkColor());
document.setUnresolvedLinkColor(jxlDocument.getUnresolvedLinkColor());
document.setRemoveUnresolvedLinks(jxlDocument.isRemoveUnresolvedLinks());
document.setIncludeURIInfo(jxlDocument.isIncludeURIInfo());
document.setBackup(jxlDocument.isSetBackupBit());
document.setEncoding(jxlDocument.getOutputEncoding());
// Sort bookmarks for sites
if (jxlDocument instanceof Site) {
Site site = (Site) jxlDocument;
if (site.isSortBookmarks()) {
document.sortBookmarks();
}
}
fireGenerationStarted(jxlDocument);
for (Iterator it = recordListenerList.iterator(); it.hasNext();) {
document.addRecordListener((RecordListener) it.next());
}
document.setFilename(jxlDocument.getFilename());
long size = destination.write(document);
jxlDocument.converted(size);
fireGenerationCompleted(jxlDocument);
logger.info("Completed conversion: " + jxlDocument.getName());
success = true;
} catch (Exception e) {
logger.severe("Could not generate document: " + e.getClass() + " " + e.getMessage());
e.printStackTrace();
} finally {
for (Iterator it = recordListenerList.iterator(); it.hasNext();) {
document.removeRecordListener((RecordListener) it.next());
}
}
} else {
logger.severe(jxlDocument.getName() + ": could not load starting URI " + jxlDocument.getUri() +
". Document cannot be generated.");
}
if (!success) {
failCount++;
}
fireConversionCompleted(jxlDocument, i + 1, jxlDocuments.length, success);
} catch (Exception e) {
logger.severe("Error initializing transformation:\n" + e.getClass().getName() + ": " +
e.getMessage());
e.printStackTrace();
}
TemporaryFile.clean();
}
closeHttpCache();
fireStatusMessage("Completed");
running = false;
conversionActive = false;
fireConversionFinished();
logUtil.close();
if (fileHandler != null) {
logUtil.removeHandler(fileHandler);
}
if ((window != null) && (failCount == 0) && ClientConfiguration.getDefault().isAutoCloseConversion()) {
window.hide();
}
}
private synchronized void closeHttpCache() {
if ((httpCache != null) && httpCache.isOpen()) {
if (ClientConfiguration.getDefault().isAutoCompactCache()) {
logger.info("Closing and compacting HTTP cache.");
fireStatusMessage("Closing and compacting HTTP cache");
httpCache.shutdownCompact();
} else {
logger.info("Closing HTTP cache.");
fireStatusMessage("Closing HTTP cache");
httpCache.close();
}
}
}
private synchronized void fireConversionCompleted(net.sf.jpluck.jxl.Document jxlDocument, int current,
int total, boolean success) {
for (Iterator iterator = conversionListenerList.iterator(); iterator.hasNext();) {
ConversionListener conversionListener = (ConversionListener) iterator.next();
conversionListener.conversionCompleted(jxlDocument, current, total, success);
}
}
private synchronized void fireConversionFinished() {
for (Iterator iterator = conversionListenerList.iterator(); iterator.hasNext();) {
ConversionListener conversionListener = (ConversionListener) iterator.next();
conversionListener.conversionFinished();
}
}
private synchronized void fireConversionStarted(net.sf.jpluck.jxl.Document jxlDocument, int current, int total) {
for (Iterator iterator = conversionListenerList.iterator(); iterator.hasNext();) {
ConversionListener conversionListener = (ConversionListener) iterator.next();
conversionListener.conversionStarted(jxlDocument, current, total);
}
}
private synchronized void fireGenerationCompleted(net.sf.jpluck.jxl.Document jxlDocument) {
for (Iterator iterator = conversionListenerList.iterator(); iterator.hasNext();) {
ConversionListener conversionListener = (ConversionListener) iterator.next();
conversionListener.generationCompleted(jxlDocument);
}
}
private synchronized void fireGenerationStarted(net.sf.jpluck.jxl.Document jxlDocument) {
for (Iterator iterator = conversionListenerList.iterator(); iterator.hasNext();) {
ConversionListener conversionListener = (ConversionListener) iterator.next();
conversionListener.generationStarted(jxlDocument);
}
}
private synchronized void fireStatusMessage(String message) {
for (Iterator iterator = conversionListenerList.iterator(); iterator.hasNext();) {
ConversionListener conversionListener = (ConversionListener) iterator.next();
conversionListener.statusMessage(message);
}
}
}