All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xmlcalabash.extensions.WaitForUpdate Maven / Gradle / Ivy

The newest version!
package com.xmlcalabash.extensions;

import com.xmlcalabash.core.XMLCalabash;
import com.xmlcalabash.core.XProcConstants;
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.WritablePipe;
import com.xmlcalabash.library.DefaultStep;
import com.xmlcalabash.runtime.XAtomicStep;
import com.xmlcalabash.util.MessageFormatter;
import com.xmlcalabash.util.TreeWriter;
import net.sf.saxon.s9api.QName;
import net.sf.saxon.s9api.SaxonApiException;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.DateUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * Created by IntelliJ IDEA.
 * User: ndw
 * Date: Oct 8, 2008
 * Time: 7:44:07 AM
 * To change this template use File | Settings | File Templates.
 */


@XMLCalabash(
        name = "cx:wait-for-update",
        type = "{http://xmlcalabash.com/ns/extensions}wait-for-update")

public class WaitForUpdate extends DefaultStep {
    private static final QName _href = new QName("","href");
    private static final QName _pause_before = new QName("","pause-before");
    private static final QName _pause_after = new QName("","pause-after");
    private static final long FILESYSTEM_WAIT = 100;
    private static final long HTTP_WAIT = 1000;
    private WritablePipe result = null;
    private URI uri = null;
    private long pauseBefore = 0;
    private long pauseAfter = 0;

    /*
     * Creates a new instance of Identity
     */
    public WaitForUpdate(XProcRuntime runtime, XAtomicStep step) {
        super(runtime,step);
    }

    public void setOutput(String port, WritablePipe pipe) {
        result = pipe;
    }

    public void reset() {
        result.resetWriter();
    }

    public void run() throws SaxonApiException {
        super.run();

        String href = getOption(_href).getString();
        URI baseURI = getOption(_href).getBaseURI();
        URI uri = baseURI.resolve(href);

        pauseBefore = getOption(_pause_before, (long) 0) * 1000;
        pauseAfter = getOption(_pause_after, (long) 0) * 1000;

        if (pauseBefore > 0) {
            try {
                Thread.sleep(pauseBefore);
            } catch (InterruptedException ie) {
                // I don't care
            }
        }

        String changed = "";
        if ("file".equals(uri.getScheme())) {
            changed = waitForFile(uri);
        } else if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
            changed = waitForHttp(uri);
        } else {
            throw new XProcException("Only http: and file: URIs are supported on cx:wait-for-update");
        }

        if (pauseAfter > 0) {
            try {
                Thread.sleep(pauseAfter);
            } catch (InterruptedException ie) {
                // I don't care
            }
        }

        TreeWriter tree = new TreeWriter(runtime);
        tree.startDocument(step.getNode().getBaseURI());
        tree.addStartElement(XProcConstants.c_result);
        tree.startContent();
        tree.addText(changed);
        tree.addEndElement();
        tree.endDocument();
        result.write(tree.getResult());
    }

    private String waitForFile(URI uri) {
        File f = new File(uri.getPath());
        boolean newFile = false;

        if (!f.exists()) {
            newFile = true;
            logger.debug(MessageFormatter.nodeMessage(step.getNode(), "Exist wait: " + f.getAbsolutePath()));
            while (!f.exists()) {
                try {
                    Thread.sleep(FILESYSTEM_WAIT);
                } catch (InterruptedException ie) {
                    // I don't care
                }
            }
        }

        long dt = f.lastModified();
        long cdt = dt;

        if (!newFile) {
            logger.debug(MessageFormatter.nodeMessage(step.getNode(), "Update wait: " + f.getAbsolutePath()));
            while (cdt == dt) {
                try {
                    Thread.sleep(FILESYSTEM_WAIT);
                } catch (InterruptedException ie) {
                    // I don't care
                }
                cdt = f.lastModified();
            }
        }

        Calendar cal = GregorianCalendar.getInstance();
        TimeZone tz = TimeZone.getDefault();
        long gmt = cdt - tz.getRawOffset();
        if (tz.useDaylightTime() && tz.inDaylightTime(cal.getTime())) {
            gmt -= tz.getDSTSavings();
        }

        cal.setTimeInMillis(gmt);
        return String.format("%1$04d-%2$02d-%3$02dT%4$02d:%5$02d:%6$02dZ",
                             cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH),
                             cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
    }

    private String waitForHttp(URI uri) {
        HttpClientBuilder builder = HttpClientBuilder.create();
        builder.setRetryHandler(new StandardHttpRequestRetryHandler(3, false));
        CloseableHttpClient client = builder.build();
        HttpContext localContext = new BasicHttpContext();
        HttpUriRequest httpRequest = new HttpHead(uri);
        HttpResponse httpResponse = null;

        httpResponse = head(client, httpRequest, localContext);
        int statusCode = httpResponse.getStatusLine().getStatusCode();
        String date = null;
        boolean newUri = false;

        if (statusCode == 404) {
            newUri = true;
            logger.debug(MessageFormatter.nodeMessage(step.getNode(), "Exist wait: " + uri.toASCIIString()));
            while (statusCode == 404) {
                try {
                    Thread.sleep(HTTP_WAIT); // one second
                } catch (InterruptedException ie) {
                    // I don't care
                }

                httpResponse = head(client, httpRequest, localContext);
                statusCode = httpResponse.getStatusLine().getStatusCode();
            }
        }

        long dt = lastModified(httpResponse);
        long cdt = dt;

        if (statusCode == 200 && !newUri) {
            logger.debug(MessageFormatter.nodeMessage(step.getNode(), "Update wait: " + uri.toASCIIString()));
            while (statusCode == 200 && cdt == dt) {
                try {
                    Thread.sleep(HTTP_WAIT);
                } catch (InterruptedException ie) {
                    // I don't care
                }
                httpResponse = head(client, httpRequest, localContext);
                statusCode = httpResponse.getStatusLine().getStatusCode();
                cdt = lastModified(httpResponse);
            }
        }

        Calendar cal = GregorianCalendar.getInstance();
        TimeZone tz = TimeZone.getDefault();
        long gmt = cdt - tz.getRawOffset();
        if (tz.useDaylightTime() && tz.inDaylightTime(cal.getTime())) {
            gmt -= tz.getDSTSavings();
        }

        cal.setTimeInMillis(gmt);
        return String.format("%1$04d-%2$02d-%3$02dT%4$02d:%5$02d:%6$02dZ",
                cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH),
                cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
    }

    private long lastModified(HttpResponse httpResponse) {
        String date = getHeader(httpResponse, "Last-modified", null);
        if (date == null) {
            date = getHeader(httpResponse, "Date", null);
        }

        Date dt = DateUtils.parseDate(date);
        return dt.getTime();
    }

    private HttpResponse head(HttpClient client, HttpUriRequest httpRequest, HttpContext localContext) {
        try {
            return client.execute(httpRequest, localContext);
        } catch (ClientProtocolException cpe) {
            throw new XProcException(cpe);
        } catch (IOException ioe) {
            throw new XProcException(ioe);
        }
    }

    private String getHeader(HttpResponse resp, String name, String def) {
        Header[] headers = resp.getHeaders(name);

        if (headers == null) {
            return def;
        }

        if (headers == null || headers.length == 0) {
            // This should never happen
            return def;
        } else {
            return headers[0].getValue();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy