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

patterntesting.runtime.log.ObjectPlayer Maven / Gradle / Ivy

Go to download

PatternTesting Runtime (patterntesting-rt) is the runtime component for the PatternTesting framework. It provides the annotations and base classes for the PatternTesting testing framework (e.g. patterntesting-check, patterntesting-concurrent or patterntesting-exception) but can be also used standalone for classpath monitoring or profiling. It uses AOP and AspectJ to perform this feat.

There is a newer version: 2.4.0
Show newest version
/*
 * Copyright (c) 2013 by Oli B.
 *
 * Licensed 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 orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 31.08.2013 by Oli B. ([email protected])
 */

package patterntesting.runtime.log;

import java.io.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.ObjectUtils;
import org.aspectj.lang.JoinPoint;
import org.slf4j.*;

import patterntesting.runtime.io.*;
import patterntesting.runtime.util.*;

/**
 * This is the counterpart to {@link ObjectRecorder} class. It can be used to
 * replay recorded objects.
 *
 * @author oliver ([email protected])
 * @since 1.3.1 (31.08.2013)
 */
public final class ObjectPlayer {

    private static final Logger log = LoggerFactory.getLogger(ObjectPlayer.class);
    private static final AbstractSerializer serializer = AbstractSerializer.getInstance();
    private final Map> loggedJoinpoints = new HashMap>();

    /**
     * Instantiates a new object player. The logged objects will be loaded from
     * the given log file.
     *
     * @param logFile the log file
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public ObjectPlayer(final File logFile) throws IOException {
        load(logFile);
    }

    /**
     * Gets the return value for the given joinpoint. The return values are
     * returned in the same order as the were recorded. I.e. if for the same
     * joinpoint first the value "1" and then the value "2" is recorded you'll
     * get first "1", then "2" as the return value.
     *
     * @param joinPoint the join point
     * @return the return value
     */
    public Object getReturnValue(final JoinPoint joinPoint) {
        String statement = JoinPointHelper.getAsLongString(joinPoint);
        if (SignatureHelper.hasReturnType(joinPoint.getSignature())) {
            return getReturnValue(statement);
        }
        log.debug("REPLAY: {}", statement);
        return null;
    }

    private Object getReturnValue(final String joinPoint) {
        Object returnValue = null;
        if (loggedJoinpoints.containsKey(joinPoint)) {
            List loggedReturnValues = loggedJoinpoints.get(joinPoint);
            returnValue = loggedReturnValues.get(0);
            if (loggedReturnValues.size() > 1) {
                loggedReturnValues.remove(0);
            }
        } else {
            log.trace("Not recorded: {}", joinPoint);
        }
        log.debug("REPLAY: {} = {}", joinPoint, returnValue);
        return returnValue;
    }

    /**
     * If you want to use an always recored object log you can load it with
     * this method. This allows you to use different files for logging and
     * loading of recorded objects.
     *
     * @param logFile the log file
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void load(final File logFile) throws IOException {
        FileInputStream istream = new BetterFileInputStream(logFile);
        try {
            if (FilenameUtils.isExtension(logFile.getName(), "gz")) {
                log.debug("Loading \"{}\" as compressed file...", logFile);
                load(new GZIPInputStream(istream));
            } else {
                log.debug("Loading \"{}\" as normal file...", logFile);
                load(istream);
            }
            log.debug("Loading \"{}\" sucessfully finished.", logFile);
        } finally {
            istream.close();
        }
    }

    /**
     * If you want to use an always recored object log you can load it with
     * this method. This allows you to use different files for logging and
     * loading of recorded objects.
     *
     * @param istream the istream
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public void load(final InputStream istream) throws IOException {
        ObjectInputStream oistream = serializer.createObjectInputStream(istream);
        try {
            while(true) {
                try {
                    String jp = (String) oistream.readObject();
                    Object retValue = oistream.readObject();
                    logToMemory(jp, retValue);
                } catch (IOException ioe) {
                    log.trace("Reading of {} stopped ({}).", istream, ioe);
                    break;
                }
            }
            log.debug("{} joinpoint(s) are read from {}.", this.loggedJoinpoints.size(), istream);
        } catch (ClassNotFoundException cnfe) {
            throw new IOException("unknown object in " + istream, cnfe);
        } finally {
            oistream.close();
        }
    }

    private void logToMemory(final String joinPoint, final Object returnValue) {
        List loggedReturnValues = new ArrayList();
        if (loggedJoinpoints.containsKey(joinPoint)) {
            loggedReturnValues = loggedJoinpoints.get(joinPoint);
        }
        loggedReturnValues.add(returnValue);
        loggedJoinpoints.put(joinPoint, loggedReturnValues);
        if (log.isTraceEnabled()) {
            log.trace("logged (" + loggedReturnValues.size() + "): {} = {}",
                    joinPoint, Converter.toString(returnValue));
        }
    }

    /**
     * Hash code.
     *
     * @return the int
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return loggedJoinpoints.hashCode();
    }

    /**
     * Equals.
     *
     * @param obj the obj
     * @return true, if successful
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(final Object obj) {
        if (!(obj instanceof ObjectPlayer)) {
            return false;
        }
        ObjectPlayer other = (ObjectPlayer) obj;
        return isEquals(this.loggedJoinpoints, other.loggedJoinpoints);
    }

    private static boolean isEquals(final Map> m1,
            final Map> m2) {
        if (m1.size() != m2.size()) {
            return false;
        }
        for (Entry> entry : m2.entrySet()) {
            if (!ObjectUtils.equals(m1.get(entry.getKey()), entry.getValue())) {
                return false;
            }
        }
        return true;
    }

    /**
     * To string.
     *
     * @return the string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return this.getClass().getSimpleName() + " with " + loggedJoinpoints.size()
                + " joinpoint(s).";
    }

}