org.archive.wayback.replay.swf.SWFReplayRenderer.java Source code

Java tutorial

Introduction

Here is the source code for org.archive.wayback.replay.swf.SWFReplayRenderer.java

Source

/*
 *  This file is part of the Wayback archival access software
 *   (http://archive-access.sourceforge.net/projects/wayback/).
 *
 *  Licensed to the Internet Archive (IA) by one or more individual 
 *  contributors. 
 *
 *  The IA licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.archive.wayback.replay.swf;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.DataFormatException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.URIException;
import org.archive.url.UsableURI;
import org.archive.url.UsableURIFactory;
import org.archive.wayback.ReplayRenderer;
import org.archive.wayback.ResultURIConverter;
import org.archive.wayback.core.CaptureSearchResult;
import org.archive.wayback.core.CaptureSearchResults;
import org.archive.wayback.core.Resource;
import org.archive.wayback.core.WaybackRequest;
import org.archive.wayback.exception.BadContentException;
import org.archive.wayback.exception.BetterRequestException;
import org.archive.wayback.exception.WaybackException;
import org.archive.wayback.replay.HttpHeaderOperation;
import org.archive.wayback.replay.HttpHeaderProcessor;
import org.archive.wayback.util.url.UrlOperations;

import com.flagstone.transform.DoAction;
import com.flagstone.transform.EventHandler;
import com.flagstone.transform.Movie;
import com.flagstone.transform.MovieTag;
import com.flagstone.transform.action.Action;
import com.flagstone.transform.action.GetUrl;
import com.flagstone.transform.action.Push;
import com.flagstone.transform.action.Table;
import com.flagstone.transform.button.DefineButton2;
import com.flagstone.transform.coder.DecoderRegistry;

/**
 * ReplayRenderer which passes embedded URLs inside flash (SWF) format content
 * through a ResultURIConverter, allowing them to be rewritten.
 * 
 * @author brad
 * 
 */
public class SWFReplayRenderer implements ReplayRenderer {
    private HttpHeaderProcessor httpHeaderProcessor;

    /**
     * @param httpHeaderProcessor
     *            to use for rewriting original HTTP headers
     */
    public SWFReplayRenderer(HttpHeaderProcessor httpHeaderProcessor) {
        this.httpHeaderProcessor = httpHeaderProcessor;
    }

    public void renderResource(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
            WaybackRequest wbRequest, CaptureSearchResult result, Resource resource,
            ResultURIConverter uriConverter, CaptureSearchResults results)
            throws ServletException, IOException, WaybackException {
        renderResource(httpRequest, httpResponse, wbRequest, result, resource, resource, uriConverter, results);
    }

    @Override
    public void renderResource(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
            WaybackRequest wbRequest, CaptureSearchResult result, Resource httpHeadersResource,
            Resource payloadResource, ResultURIConverter uriConverter, CaptureSearchResults results)
            throws ServletException, IOException, WaybackException {

        try {

            // copy HTTP response code:
            HttpHeaderOperation.copyHTTPMessageHeader(httpHeadersResource, httpResponse);

            // load and process original headers:
            Map<String, String> headers = HttpHeaderOperation.processHeaders(httpHeadersResource, result,
                    uriConverter, httpHeaderProcessor);

            // The URL of the resource, for resolving embedded relative URLs:
            URL url = null;
            try {
                url = new URL(result.getOriginalUrl());
            } catch (MalformedURLException e1) {
                e1.printStackTrace();
                throw new IOException(e1.getMessage());
            }
            // the date to associate with the embedded, rewritten URLs:
            String datespec = result.getCaptureTimestamp();
            SWFUrlRewriter rw = new SWFUrlRewriter(uriConverter, url, datespec);

            // OK, try to read the input movie:
            Movie movie = getRobustMovie(RobustMovieDecoder.DECODE_RULE_NULLS);

            try {
                movie.decodeFromStream(payloadResource);
            } catch (DataFormatException e1) {
                throw new BadContentException(e1.getLocalizedMessage());
            }
            Movie outMovie = new Movie(movie);

            List<MovieTag> inTags = movie.getObjects();
            ArrayList<MovieTag> outTags = new ArrayList<MovieTag>();
            for (MovieTag tag : inTags) {
                outTags.add(rewriteTag(rw, tag));
            }
            outMovie.setObjects(outTags);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                outMovie.encodeToStream(baos);
            } catch (DataFormatException e) {
                throw new BadContentException(e.getLocalizedMessage());
            }

            // put the new corrected length:
            headers.put(HttpHeaderOperation.HTTP_LENGTH_HEADER, String.valueOf(baos.size()));

            // send the new headers:
            HttpHeaderOperation.sendHeaders(headers, httpResponse);

            // and copy the stored up byte-stream:
            baos.writeTo(httpResponse.getOutputStream());
        } catch (Exception e) {

            // Redirect to identity if there are any issues
            throw new BetterRequestException(UrlOperations.computeIdentityUrl(wbRequest));
        }
    }

    private Movie getRobustMovie(int decodeRule) {
        Movie movie = new Movie();

        DecoderRegistry registry = DecoderRegistry.getDefault();
        RobustMovieDecoder decoder = new RobustMovieDecoder();
        decoder.setDelegate(registry.getMovieDecoder());
        decoder.setDecodeRule(decodeRule);
        registry.setMovieDecoder(decoder);
        movie.setRegistry(registry);

        return movie;
    }

    private MovieTag rewriteTag(SWFUrlRewriter rw, MovieTag tag) {
        if (tag instanceof DoAction) {
            DoAction doAction = (DoAction) tag;
            doAction.setActions(rewriteActions(rw, doAction.getActions()));
        } else if (tag instanceof DefineButton2) {

            DefineButton2 defButton2 = (DefineButton2) tag;
            defButton2.setEvents(rewriteEventHandlers(rw, defButton2.getEvents()));
        }
        return tag;
    }

    private List<EventHandler> rewriteEventHandlers(SWFUrlRewriter rw, List<EventHandler> handlers) {
        ArrayList<EventHandler> newActions = new ArrayList<EventHandler>();
        for (EventHandler handler : handlers) {
            handler.setActions(rewriteActions(rw, handler.getActions()));
            newActions.add(handler);
        }
        return newActions;
    }

    private List<Action> rewriteActions(SWFUrlRewriter rw, List<Action> actions) {
        ArrayList<Action> newActions = new ArrayList<Action>();
        for (Action action : actions) {
            if (action instanceof Table) {

                Table table = (Table) action;
                table.setValues(rewriteStringValues(rw, table.getValues()));
                newActions.add(table);

            } else if (action instanceof Push) {

                Push push = (Push) action;

                newActions.add(new Push(rewriteObjectValues(rw, push.getValues())));

            } else if (action instanceof GetUrl) {

                GetUrl getUrl = (GetUrl) action;
                newActions.add(new GetUrl(rewriteString(rw, getUrl.getUrl()), getUrl.getTarget()));

            } else {
                newActions.add(action);
            }
        }
        return newActions;
    }

    private List<Object> rewriteObjectValues(SWFUrlRewriter rw, List<Object> values) {

        ArrayList<Object> nvals = new ArrayList<Object>();
        for (int i = 0; i < values.size(); i++) {
            Object orig = values.get(i);
            if (orig instanceof String) {
                nvals.add(rewriteString(rw, (String) orig));
            } else {
                nvals.add(orig);
            }
        }
        return nvals;
    }

    private List<String> rewriteStringValues(SWFUrlRewriter rw, List<String> values) {

        ArrayList<String> nvals = new ArrayList<String>();
        for (int i = 0; i < values.size(); i++) {
            nvals.add(rewriteString(rw, values.get(i)));
        }
        return nvals;
    }

    private String rewriteString(SWFUrlRewriter rw, String original) {
        if (original.startsWith("http://")) {
            // System.err.format("Rewrite(%s)\n",original);
            return rw.rewrite(original);
        }
        return original;
    }

    private class SWFUrlRewriter {
        UsableURI baseUrl = null;
        ResultURIConverter converter;
        String datespec;

        public SWFUrlRewriter(ResultURIConverter converter, URL baseUrl, String datespec) {
            this.datespec = datespec;
            this.converter = converter;
            try {
                this.baseUrl = UsableURIFactory.getInstance(baseUrl.toExternalForm());
            } catch (URIException e) {
                e.printStackTrace();
            }

        }

        public String rewrite(String url) {
            try {
                String resolved = url;
                if (baseUrl != null) {
                    resolved = UsableURIFactory.getInstance(baseUrl, url).toString();
                }
                return converter.makeReplayURI(datespec, resolved);
            } catch (URIException e) {
                e.printStackTrace();
            }
            return url;
        }
    }
}