    001// Copyright 2008-2014 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007// http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.corelib.internal;
    016
    017import java.io.IOException;
    018import java.io.ObjectOutputStream;
    019
    020import org.apache.tapestry5.ComponentAction;
    021import org.apache.tapestry5.runtime.Component;
    022import org.apache.tapestry5.services.ClientDataEncoder;
    023import org.apache.tapestry5.services.ClientDataSink;
    024import org.slf4j.Logger;
    025
    026/**
    027 * Used to collection component actions, with the ultimate goal being the creation of a MIME-encoded string of the
    028 * serialization of those actions.
    029 */
    030public class ComponentActionSink
    031{
    032    private final Logger logger;
    033
    034    private final ObjectOutputStream stream;
    035
    036    private final ClientDataSink sink;
    037
    038    private boolean empty = true;
    039
    040    public ComponentActionSink(Logger logger, ClientDataEncoder encoder)
    041    {
    042        this.logger = logger;
    043
    044        sink = encoder.createSink();
    045
    046        stream = sink.getObjectOutputStream();
    047    }
    048
    049    public <T> void store(T component, ComponentAction<T> action)
    050    {
    051        streamAction(component, false, action);
    052    }
    053
    054    public <T> void storeCancel(T component, ComponentAction<T> action)
    055    {
    056        streamAction(component, true, action);
    057    }
    058
    059    private <T> void streamAction(T component, boolean cancel, ComponentAction<T> action)
    060    {
    061        Component castComponent = (Component) component;
    062        assert action != null;
    063
    064        String completeId = castComponent.getComponentResources().getCompleteId();
    065
    066        logger.debug("Storing {}: {} {}", cancel ? "cancel action": "action", completeId, action);
    067
    068        try
    069        {
    070            // Writing the complete id is not very efficient, but the GZip filter
    071            // should help out there.
    072            stream.writeUTF(completeId);
    073            stream.writeBoolean(cancel);
    074            stream.writeObject(action);
    075        }
    076        catch (IOException ex)
    077        {
    078            throw new RuntimeException(String.format("Error serializing component action for component %s: %s", completeId, ex), ex);
    079        }
    080
    081        empty = false;
    082    }
    083
    084    /** @since 5.2.0 */
    085    public boolean isEmpty()
    086    {
    087        return empty;
    088    }
    089
    090    public String getClientData()
    091    {
    092        return sink.getClientData();
    093    }
    094}