Cloner.java

package org.opentrafficsim.road.network.factory.xml.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import org.opentrafficsim.road.network.factory.xml.XmlParserException;
import org.opentrafficsim.xml.generated.CseLane;
import org.opentrafficsim.xml.generated.CseShoulder;
import org.opentrafficsim.xml.generated.CseStripe;
import org.opentrafficsim.xml.generated.RoadLayout;

/**
 * Cloner makes a deep clone of any serializable object with serializable fields.
 * <p>
 * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
 * </p>
 * @author <a href="https://github.com/averbraeck" target="_blank">Alexander Verbraeck</a>
 */
public final class Cloner
{
    /** */
    private Cloner()
    {
        // utility class
    }

    /**
     * Clone an object that is serializable and that has serializable fields.
     * @param object the object to clone
     * @param <T> the type of the object to clone
     * @return the clone of the object
     * @throws XmlParserException on cloning error
     */
    @SuppressWarnings("unchecked")
    public static <T> T clone(final T object) throws XmlParserException
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (T) ois.readObject();
        }
        catch (SecurityException | IOException | ClassNotFoundException exception)
        {
            throw new XmlParserException(exception);
        }
    }

    /**
     * Clone the BasicRoadLayout, as not all DJUNIT types are serializable...
     * @param in the object to clone
     * @return the cloned object
     */
    public static RoadLayout cloneRoadLayout(final RoadLayout in)
    {
        RoadLayout rl = new RoadLayout();
        rl.setLaneKeeping(in.getLaneKeeping());
        rl.setLinkType(in.getLinkType());
        rl.getSpeedLimit().addAll(in.getSpeedLimit());
        for (Object o : in.getStripeOrLaneOrShoulder())
        {
            if (o instanceof CseLane)
            {
                CseLane lane = (CseLane) o;
                CseLane lc = new CseLane();
                lc.setCenterOffset(lane.getCenterOffset());
                lc.setCenterOffsetEnd(lane.getCenterOffsetEnd());
                lc.setCenterOffsetStart(lane.getCenterOffsetStart());
                lc.setLeftOffset(lane.getLeftOffset());
                lc.setLeftOffsetEnd(lane.getLeftOffsetEnd());
                lc.setLeftOffsetStart(lane.getLeftOffsetStart());
                lc.setRightOffset(lane.getRightOffset());
                lc.setRightOffsetEnd(lane.getRightOffsetEnd());
                lc.setRightOffsetStart(lane.getRightOffsetStart());
                lc.setLaneType(lane.getLaneType());
                lc.setId(lane.getId());
                lc.setWidth(lane.getWidth());
                lc.setWidthEnd(lane.getWidthEnd());
                lc.setWidthStart(lane.getWidthStart());
                lc.getSpeedLimit().addAll(lane.getSpeedLimit());
                rl.getStripeOrLaneOrShoulder().add(lc);
            }

            else if (o instanceof CseShoulder)
            {
                CseShoulder shoulder = (CseShoulder) o;
                CseShoulder sc = new CseShoulder();
                sc.setCenterOffset(shoulder.getCenterOffset());
                sc.setCenterOffsetEnd(shoulder.getCenterOffsetEnd());
                sc.setCenterOffsetStart(shoulder.getCenterOffsetStart());
                sc.setLeftOffset(shoulder.getLeftOffset());
                sc.setLeftOffsetEnd(shoulder.getLeftOffsetEnd());
                sc.setLeftOffsetStart(shoulder.getLeftOffsetStart());
                sc.setRightOffset(shoulder.getRightOffset());
                sc.setRightOffsetEnd(shoulder.getRightOffsetEnd());
                sc.setRightOffsetStart(shoulder.getRightOffsetStart());
                sc.setId(shoulder.getId());
                sc.setWidth(shoulder.getWidth());
                sc.setWidthEnd(shoulder.getWidthEnd());
                sc.setWidthStart(shoulder.getWidthStart());
                rl.getStripeOrLaneOrShoulder().add(sc);
            }

            else if (o instanceof CseStripe)
            {
                CseStripe stripe = (CseStripe) o;
                CseStripe sc = new CseStripe();
                sc.setCenterOffset(stripe.getCenterOffset());
                sc.setCenterOffsetEnd(stripe.getCenterOffsetEnd());
                sc.setCenterOffsetStart(stripe.getCenterOffsetStart());
                sc.setId(stripe.getId());
                sc.setDrawingWidth(stripe.getDrawingWidth());
                sc.setType(stripe.getType());
                rl.getStripeOrLaneOrShoulder().add(sc);
            }
        }
        return rl;
    }
}