Package com.ericsson.ssa.sip.timer

Source Code of com.ericsson.ssa.sip.timer.ServletTimerImpl

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
* Copyright (c) Ericsson AB, 2004-2008. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.ericsson.ssa.sip.timer;

import com.ericsson.ssa.config.ConvergedContext;
import com.ericsson.ssa.sip.LifeCycle;
import com.ericsson.ssa.sip.PrivilegedGetSipSessionManagerRegistry;
import com.ericsson.ssa.sip.RemoteLockException;
import com.ericsson.ssa.sip.RemoteLockRuntimeException;
import com.ericsson.ssa.sip.SipApplicationSessionImpl;
import com.ericsson.ssa.sip.SipSessionManager;
import com.ericsson.ssa.sip.SipSessionManagerRegistry;
import com.ericsson.ssa.sip.IWRHandler;
import com.ericsson.ssa.sip.persistence.ReplicationUnitOfWork;
import com.ericsson.ssa.utils.UUIDUtil;
import com.ericsson.ssa.container.sim.InvocationContextUtil;

import org.apache.catalina.Globals;

import org.jvnet.glassfish.comms.deployment.backend.SipApplicationListeners;
import org.jvnet.glassfish.comms.util.LogUtil;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Externalizable;
import java.io.Serializable;

import java.security.AccessController;

import java.util.UUID;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.sip.ServletTimer;
import javax.servlet.sip.TimerListener;


public class ServletTimerImpl extends ServletTimerImplBase
    implements Externalizable, LifeCycle {
    private static Logger logger = LogUtil.SIP_LOGGER.getLogger();

    /**
     * Class identifier for serialization
     */
    private static final long serialVersionUID = 8123619219185134043L;

    /** The serialized format versioning. 1 = first version. */
    private static final short serializedFormVersion = 1;

    /**
     * A future delayed scheduled action to be run
     */
    private ScheduledFuture<?> future;

    /**
     * Information about what this timer is.
     */
    private Serializable info;

    /**
     * The id of the associated SipApplicationSession
     */
    protected String sasId = null;

    /**
     * The associated session manager
     */
    private volatile SipSessionManager sipSessionManager;

    /**
     * Absolute time in milliseconds for next execution.
     */
    private long scheduledExecutionTime = 0;

    /**
     * Recent Timer Expiration in  milliseconds.
     */
    private long recentExpiredTime = 0;

    /**
     * Delay from creation of timer to execution
     */
    private long delay = 0;

    /**
     * Period between executions. Only applicable for repeating timers.
     */
    private long period = 0;

    /**
     * Number of times execution has happened.
     */
    private long numInvocations = 0;

    /**
     * Absolute time for first execution.
     */
    private long firstExecution = 0;

    /**
     * Whether executions should be scheduled with fixed delay.
     *
     * @see java.util.Timer for semantics.
     */
    private boolean fixedDelay = false;

    /**
     * Whether this timer is persistent.
     */
    private boolean persistent = false;

    /**
     * Registered listener that will get a timeout event when executed.
     */
    private TimerListener listener;
    private transient AtomicBoolean listenerLookedUp = null;

    /**
     * Whether execution should be repeated.
     */
    private boolean isRepeatingTimer = true;

    /**
     * The unique id of this timer.
     */
    protected String id = null;

    /**
     * Constructor for non-repeating timer.
     *
     * @param manager The associated session manager
     * @param sas The SipApplicationSession with which this ServletTimer has
     * been associated
     * @param info Information about the timer
     * @param delay Delay until execution
     * @param listener Listener that will get timeout events.
     * @param isPersistent true if this ServletTimer is persistent, false
     * otherwise
     */
    public ServletTimerImpl(SipSessionManager manager,
        SipApplicationSessionImpl sas, Serializable info, long delay,
        TimerListener listener, boolean isPersistent) {
        this(manager, sas, info, delay, false, 0, listener, isPersistent);
        isRepeatingTimer = false;
    }

    /**
     * Constructor for repeating times
     *
     * @param manager The associated session manager
     * @param sas The SipApplicationSession with which this ServletTimer has
     * been associated
     * @param info Information about the timer
     * @param delay Delay until first execution
     * @param fixedDelay Whether fixed delay mode should be used
     * @param period Period between execution
     * @param listener Listener that will get timeout events.
     * @param isPersistent true if this ServletTimer is persistent, false
     * otherwise
     */
    public ServletTimerImpl(SipSessionManager manager,
        SipApplicationSessionImpl sas, Serializable info, long delay,
        boolean fixedDelay, long period, TimerListener listener,
        boolean isPersistent) {
        this.sipSessionManager = manager;
        this.sasId = sas.getId();
        this.info = info;
        this.delay = delay;
        scheduledExecutionTime = delay + System.currentTimeMillis();
        this.fixedDelay = fixedDelay;
        this.period = period;
        this.listener = listener;
        setPFieldPersistent(isPersistent);
        this.listenerLookedUp = new AtomicBoolean(true);

        id = UUIDUtil.randomUUID();
        sas.addServletTimer(this);
    }

    public ServletTimerImpl() { // default constructor for externalization.
    }
   
    /**
     * @serialData See serialized form version 1 in #readExternal(ObjectInput in)
     *
     * @param out the stream to write the object members
     * @throws IOException
     */
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeShort(serializedFormVersion);

        out.writeUTF(getIdForSerial());
        out.writeObject(info);

        out.writeUTF(sasId);

        out.writeLong(scheduledExecutionTime);
        out.writeLong(recentExpiredTime);
        out.writeLong(delay);
        out.writeLong(period);
        out.writeLong(numInvocations);
        out.writeLong(firstExecution);
        out.writeBoolean(fixedDelay);
        out.writeBoolean(isRepeatingTimer);
        out.writeBoolean(persistent);
    }

    /**
     * @serialData first field is an short and represents the serializedFormVersion.<br>
     * <h3>Data layout for serializedFormVersion = 1 follows</h3>
     *
     * <li>field is a <b>String</b> and represents timerId field</li>
     * <li>field is a <b>Serializable</b> and represents attached info object for this timer</li>
     * <li>field is a <b>String</b> and represents applicationId field</li>
     * <li>field is a <b>String</b> and represents sip applicationSessionId field</li>
     * <li>field is a <b>Long</b> and represents the scheduledExecutionTime field as absolute time</li>
     * <li>field is a <b>Long</b> and represents the delay field in milliseconds</li>
     * <li>field is a <b>Long</b> and represents the period field in milliseconds</li>
     * <li>field is a <b>Long</b> and represents the numInvocations field</li>
     * <li>field is a <b>Long</b> and represents the firstExecution field</li>
     * <li>field is a <b>Boolean</b> and represents the fixedDelay field</li>
     * <li>field is a <b>Boolean</b> and represents the isRepeatingTimer field</li>
     * <li>field is a <b>Boolean</b> and represents the persistent field</li>
     *
     * @param in the stream to read the object members
     * @throws IOException is thrown when unsupported version is detected
     * @throws ClassNotFoundException
     */
    public void readExternal(ObjectInput in)
        throws IOException, ClassNotFoundException {
        short readSerializedFormVersion = in.readShort();

        switch (readSerializedFormVersion) {
        case 1:
            id = in.readUTF();
            info = (Serializable) in.readObject();

            sasId = in.readUTF();

            scheduledExecutionTime = in.readLong();
            recentExpiredTime = in.readLong();
            delay = in.readLong();
            period = in.readLong();
            numInvocations = in.readLong();
            firstExecution = in.readLong();
            fixedDelay = in.readBoolean();
            isRepeatingTimer = in.readBoolean();
            persistent = in.readBoolean();
            listenerLookedUp = new AtomicBoolean(false); // Need to explicitely instantiate.

            break;

        default:
            throw new IOException("Unable to deserialize into " +
                this.getClass().getName() +
                    " with serialVersionUID = " + serialVersionUID +
                " due to unknown serializedFormVersion of " +
                readSerializedFormVersion);
        }
    }

    /**
     * @see com.ericsson.ssa.sip.timer.ServletTimerImpl#getAppId()
     */
    public String getAppId() {
        return sipSessionManager != null
                ? sipSessionManager.getApplicationId() : null;
    }

    // --- PField accessors ---
    @Override
    protected String getPFieldId() {
        return id;
    }

    @Override
    protected ScheduledFuture<?> getPFieldFuture() {
        return future;
    }

    @Override
    protected void setFieldFuture(ScheduledFuture<?> future) {
        this.future = future;
    }

    @Override
    protected Serializable getPFieldInfo() {
        return info;
    }

    @Override
    protected SipApplicationSessionImpl getPFieldAppSession() {
        SipApplicationSessionImpl sas = null;

        try {
            SipSessionManager ssm = getSipSessionManager();
            if(ssm != null) {
                sas = ssm.findSipApplicationSession(sasId);
            }
        } catch (RemoteLockException e) {
            throw new RemoteLockRuntimeException(e);
        }

        if (sas == null) {
            logger.log(Level.WARNING,
                "SipApplication Session " + sasId + " not found");
        }

        return sas;
    }

    @Override
    protected long getPFieldFirstExecution() {
        return firstExecution;
    }

    @Override
    protected long getPFieldPeriod() {
        return period;
    }

    @Override
    protected long getPFieldScheduledExecutionTime() {
        return scheduledExecutionTime;
    }

    @Override
    protected long incrementAndGetPFieldNumInvocations() {
        return ++numInvocations;
    }

    @Override
    protected void setPFieldFirstExecution(long firstExecution) {
        this.firstExecution = firstExecution;
    }

    @Override
    protected void setPFieldScheduledExecutionTime(long scheduledExecutionTime) {
        this.scheduledExecutionTime = scheduledExecutionTime;
    }

    @Override
    protected long getPFieldRecentExpiredTime() {
        return recentExpiredTime;
    }

    @Override
    protected void setPFieldRecentExpiredTime(long recentExpiredTime) {
        this.recentExpiredTime = recentExpiredTime;
    }

    @Override
    protected long getPFieldDelay() {
        return delay;
    }

    @Override
    protected boolean getPFieldFixedDelay() {
        return fixedDelay;
    }

    @Override
    protected boolean getPFieldPersistent() {
        return persistent;
    }

    @Override
    protected void setPFieldPersistent(boolean p) {
        this.persistent = p;
    }

    @Override
    protected boolean getPFieldIsRepeatingTimer() {
        return isRepeatingTimer;
    }

    @Override
    protected synchronized TimerListener getPFieldListener() {
        if (!listenerLookedUp.getAndSet(true)) {
            SipSessionManager sipSessionManager = getSipSessionManager();

            if (sipSessionManager != null) {
                ConvergedContext ctx = sipSessionManager.getContext();

                if (ctx != null) {
                    SipApplicationListeners appListeners = ctx.getSipApplicationListeners();

                    if (appListeners != null) {
                        listener = appListeners.getTimerListener();
                    }
                }
            }
        }

        return listener;
    }

    /**
     * sipSessionManager will be null after deserializing the ST object
     * back from the ObjectInputStream. So, the deserializer must explicitly
     * set the sipSessionManager after deserialization, which means that the
     * serialization/deserialization of the ST object should only be done in a
     * context using the appropriate SipStore interfaces.
     *
     * @return the sip session manager.
     */
    protected SipSessionManager getSipSessionManager() {
        return sipSessionManager;
    }

    /**
     * The sipSessionManager must be explicitly set by the deserializer after
     * deserializing the ST object back from the ObjectInputStream.
     *
     * @see org.jvnet.glassfish.comms.replication.sessmgmt.ServletTimerStoreImpl
     *
     * @param manager sip session mananger.
     */
    public void setSipSessionManager(SipSessionManager manager) {
        this.sipSessionManager = manager;
    }

    protected String getFullyQualifiedId() {
        return "ServletTimer with id " + getAppId() + ":" + getId();
    }

    private void restartTimer() {
        // Rescedule timer
        TimerServiceImpl.getInstance().rescheduleTimer(this);
    }

    /*
     * Cancels this timer.
     */
    @Override
    public void cancel(boolean mayInterruptIfRunning) {
        cancel(mayInterruptIfRunning, true);
    }

    /*
     * Cancels this timer.
     *
     * @param mayInterruptIfRunning
     * @param removeFromParentSAS true if this ServletTimer is also
     * going to be removed from its parent SipApplicationSession, and false
     * otherwise
     */
    @Override
    public void cancel(boolean mayInterruptIfRunning,
                       boolean removeFromParentSAS) {
        super.cancel(mayInterruptIfRunning, removeFromParentSAS);
        SipSessionManager ssm = getSipSessionManager();
        if(ssm != null) {
            ssm.removeServletTimer(this);
        }
        if(removeFromParentSAS && !timeoutInProgress) {
            IWRHandler.getInstance().handle(this);
        }
    }

    public String getID() {
        throw new RuntimeException("Not yet implemented ");
    }


    /**
     * Gets the id to be included in the serialized representation of this
     * ServletTimer. Normally, this will be the same as the id of
     * this ServletTimer, but subclasses may override this method to
     * return null or an empty string (for optimization purposes), if they
     * are able to obtain the id from another source after deserialization.
     */
    protected String getIdForSerial() {
        return id;
    }


    public long getTimeRemaining() {
        return getPFieldScheduledExecutionTime() - System.currentTimeMillis();
    }

    /*
     * (non-Javadoc)
     * @see com.ericsson.ssa.sip.LifeCycle#activate()
     */
    public boolean activate() {
        // Add to active cache
        SipSessionManager mgr = getSipSessionManager();

        if (mgr != null) {
            ServletTimer st = mgr.addServletTimer(this);

            if (st != null) {
                // While this thread has been in the process of loading the
                // requested ServletTimer, and is now trying to activate it,
                // another thread has also loaded the same ServletTimer, and
                // has already added it to the active cache. Abort activation.
                return true;
            }
        }

        // Restart timer if not already started
        if (future == null) {
            restartTimer();
        }

        return true;
    }

    /*
     * (non-Javadoc)
     * @see com.ericsson.ssa.sip.LifeCycle#passivate()
     */
    public void passivate() {
        // Remove from active cache
        SipSessionManager mgr = getSipSessionManager();

        if (mgr != null) {
            mgr.removeServletTimer(this);
        }

        stop(true);
    }

    private Object fireTimer() throws Exception {
        InvocationContextUtil.preInvoke(getSipSessionManager());
        try {
            return super.call();
        } finally {
            InvocationContextUtil.preInvoke(getSipSessionManager());
        }
    }

    @Override
    public Object call() throws Exception {

        SipApplicationSessionImpl sas = (SipApplicationSessionImpl)
            getApplicationSession();
        if (sas != null && sas.hasServletTimer(getId()) && sas.isValid()) {
            if (sas.isReplicationEnabled()) {
                // Instantiate a unit-of-work to collect any entities/artifacts
                // modified during TimerListener invocation.
                // If unit-of-work already exists, leverage it instead of
                // creating a new one
                if (ReplicationUnitOfWork.getThreadLocalUnitOfWork() == null) {
                    ReplicationUnitOfWork unitOfWork =
                        new ReplicationUnitOfWork();
                    unitOfWork.lockApplicationSession(sas);
                    try {
                        // fire timer
                        return fireTimer();
                    } finally {
                        // Save modified entities (if any), and unlock the
                        // uow
                        unitOfWork.saveAndUnlock();
                    }
                } else {
                    // reuse the current uow
                    return fireTimer();
                }
            } else {
                // fire timer
                return fireTimer();
            }
        } else {
            // not a child (anymore)
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE,
                    "Timeout ignored for ServletTimer " + getId() +
                    " because it has been orphaned, or its parent SAS " +
                    sas + " is no longer valid");
                logger.log(Level.FINE, "Canceling ServletTimer " +
                           getId());
            }
            // Expire without removing from SAS, see IT 1375
            cancel(true, false);
            return null;                   
        }
    }

    /*
     * (non-Javadoc)
     *
     * @see java.lang.Object#toString()
     */
    public String toString() {
        StringBuilder sb = new StringBuilder();
        String fullyQualifiedId = getFullyQualifiedId();

        if (fullyQualifiedId != null) {
            sb.append(fullyQualifiedId).append('\n');
        }

        sb.append("Info = ").append(getPFieldInfo()).append('\n');
        sb.append("Scheduled execution time = ")
          .append(getPFieldScheduledExecutionTime()).append('\n');
        sb.append("Time now = ").append(System.currentTimeMillis()).append('\n');
        sb.append("SipApplicationSession = ").append(sasId).append('\n');
        sb.append("ScheduledFuture = ").append(getPFieldFuture()).append('\n');
        sb.append("Delay = ").append(getPFieldDelay()).append('\n');

        return sb.toString();
    }
}
TOP

Related Classes of com.ericsson.ssa.sip.timer.ServletTimerImpl

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.