Package dk.brics.jwig

Source Code of dk.brics.jwig.XMLProducer

package dk.brics.jwig;

import dk.brics.jwig.server.ThreadContext;
import dk.brics.jwig.util.RandomString;
import dk.brics.xact.ToXMLable;
import dk.brics.xact.XML;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* Handler that produces XML data when an object it depends on has been changed.
*/
@Regenerable
public class XMLProducer extends AbstractHandler implements ToXMLable {

    private final String pageurl;

    private final Object[] objs;

    /**
     * Constructs a new XML producer.
     * When notified by one of the given objects, the <code>run</code>
     * method is invoked for recomputing the XML data, and the active clients are informed.
     * The <code>run</code> method is assumed to be 'safe' (in the HTTP sense).
     *
     * @see WebContext#update(Object)
     * @see EventHandler#getProducer()
     */
    public XMLProducer(Object... dependencies) {
        super(dependencies);
        this.objs = dependencies;
        pageurl = ThreadContext.get().getRequestURL();
    }

    /**
     * Invoked when a new result has been computed.
     * Invalidates the cached value and informs the active clients.
     */
    public void update() { // FIXME: invoke from DependencyMap on notifications
        ThreadContext.getCache().remove(pageurl);
        ThreadContext.getSynchronizer().update(getHandlerIdentifier());
    }

    /**
     * Returns an XML value obtained by invoking <code>run</code>, together with
     * a JavaScript instruction for automatic updating.
     */
    @Override
  public XML toXML() {
        XML xml = invokeRun();
        Response p = makeResponse(xml); //Make a cached response that stores the value of the XML generated by the producer (and tag it with an ETAG)
        String handlerCacheIdentifier = getCacheAugmentedString(getHandlerIdentifier());

        ThreadContext.getCache().put(handlerCacheIdentifier, p); //Manually store the value in the cache for later requests
        String id = "s" + RandomString.get(12);
        return XML.parseTemplate(
                "<script type=\"text/javascript\" id=[ID]>jwig.startXML('<[URL]>','\"<[ETAG]>\"','<[ID]>')</script>" +
                        "<[VALUE]>" +
                        "<script type=\"text/javascript\">jwig.endXML()</script>")
                .plug("URL", handlerCacheIdentifier)
                .plug("VALUE", xml)
                .plug("ETAG", p.getETag()) //This ETAG is used to the check the cache for the XML generated by the producer
                .plug("ID", id);
    }

    /**
     * Invokes the <code>run</code> and returns the XML result.
     */
    XML invokeRun() {
        try {
            for (Object obs : objs) {
                if (obs != null) {
                    ThreadContext.getDependencyMap().addDependency(this, obs);
                }
            }
            ThreadContext c = ThreadContext.get();
            Method m = getClass().getDeclaredMethod("run");
            XMLProducer previous = c.getProducer();
            c.setProducer(this);
            m.setAccessible(true);
            XML xml = (XML) m.invoke(this);
            c.setProducer(previous);
            return xml;
        } catch (NoSuchMethodException e) {
            throw new JWIGException(e);
        } catch (IllegalArgumentException e) {
            throw new JWIGException(e);
        } catch (IllegalAccessException e) {
            throw new JWIGException(e);
        } catch (InvocationTargetException e) {
            throw new JWIGException(e);
        }
    }

    /**
     * Constructs a cached response.
     * The response is also wrapped into a dummy root element.
     */
    private Response makeResponse(XML xml) {
        xml = wrap(xml);
        Response p = new Response();
        p.setXML(xml);
        p.setContentType("text/plain");
        return p;
    }

    private XML wrap(XML xml) {
        if (xml != null)
          xml = XML.parseTemplate("<div/>").setContent(xml);
        return xml;
    }

    /**
     * Invokes the <code>run</code> method of the handler, caches the result, and sends it to the client.
     */
    @Override
    Object process(String referer) {
        XML xml = wrap(invokeRun());
        getResponse().setContentType("text/plain");
        return xml;
    }

    /**
     * Invoked when the current response is invalidated.
     */
    @Override
    public void destroy() {
        ThreadContext.getCache().remove(getHandlerIdentifier());
    }
}
TOP

Related Classes of dk.brics.jwig.XMLProducer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.