Package org.jvnet.glassfish.comms.replication.sessmgmt

Source Code of org.jvnet.glassfish.comms.replication.sessmgmt.HAServletTimer

/*
* 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 org.jvnet.glassfish.comms.replication.sessmgmt;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.sip.TimerListener;

import org.jvnet.glassfish.comms.util.LogUtil;

import com.ericsson.ssa.sip.PersistentSipSessionManagerBase;
import com.ericsson.ssa.sip.RemoteLockException;
import com.ericsson.ssa.sip.SipApplicationSessionImpl;
import com.ericsson.ssa.sip.SipApplicationSessionUtil;
import com.ericsson.ssa.sip.SipSessionManager;
import com.ericsson.ssa.sip.persistence.ReplicationUnitOfWork;
import com.ericsson.ssa.sip.timer.ServletTimerImpl;
import com.sun.appserv.ha.uow.ReplicableEntity;
import com.sun.enterprise.ee.web.sessmgmt.ReplicationState;
import com.sun.enterprise.ee.web.sessmgmt.ReplicationUtil;

/**
* Class representing a replicating ServletTimer.
*/
public class HAServletTimer extends ServletTimerImpl implements ReplicableEntity {

    private static final Logger LOGGER = LogUtil.SSR_LOGGER.getLogger();

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private transient boolean isDirty = false;

    /** The serialized format versioning. */
    private static final short serializedFormVersion  = 2;

    // The version of this ServletTimer
    private transient AtomicLong version;
    private transient ServletTimerExtraParams extraParams;
    private transient String previousOwnerInstanceName;
    private transient String currentOwnerInstanceName;
    private transient long wiggledExpirationTime;
    private transient AtomicBoolean isSuspect
        = new AtomicBoolean(false);   
    private transient boolean wasLockedOnRemoteInstance = false;
    private transient boolean isBeingReplicated = false;
    protected transient boolean isReplicated = false;
    protected long internalLastAccessedTime = -1L;

    /**
     * Constructor for non-repeating timer.
     *
     * @param manager The associated session manager
     * @param sasId 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.
     */
    public HAServletTimer(SipSessionManager manager,
        SipApplicationSessionImpl sas, Serializable info, long delay,
        TimerListener listener) {
        super(manager, sas, info, delay, listener, true);
        setWiggledExpirationTime(calculateWiggledTime(getPFieldScheduledExecutionTime()));
        version = new AtomicLong(-1);
        extraParams = new ServletTimerExtraParams(this);
        currentOwnerInstanceName = ReplicationUtil.getInstanceName();
    }

    /**
     * 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.
     */
    public HAServletTimer(SipSessionManager manager,
        SipApplicationSessionImpl sas, Serializable info, long delay,
        boolean fixedDelay, long period, TimerListener listener) {
        super(manager, sas, info, delay, fixedDelay, period, listener,
              true);
        setWiggledExpirationTime(calculateWiggledTime(getPFieldScheduledExecutionTime()));
        version = new AtomicLong(-1);
        extraParams = new ServletTimerExtraParams(this);
        currentOwnerInstanceName = ReplicationUtil.getInstanceName();
    }

    public HAServletTimer() { // default constructor for externalization.
    }

    public String getBeKey() {
        return SipApplicationSessionUtil.getSipApplicationKey(getParentSASId());
    }
   
    /**
     * Gets the name of the instance.that previously owned this
     * ServletTimer.
     *
     * @return The name of the instance that previously owned this
     *         ServletTimer
     */
    public String getPreviousOwnerInstanceName() {
        return previousOwnerInstanceName;
    }

    /**
     * Gets the name of the instance.that currently owns this
     * ServletTimer.
     *
     * @return The name of the instance that currently owns this
     *         ServletTimer
     */
    public String getCurrentOwnerInstanceName() {
        return currentOwnerInstanceName;
    }

    /**
     * Gets the wiggled expiration time.
     * Which is the expiration time plus a randomized
     * wiggle amount in order to spread out the activation
     * of replica servlet timers that otherwise would have
     * had the same expiration
     *
     * The wiggled expiration time is only checked by the
     * reaper thread
     *
     * @return The wiggled expiration time
     */   
    public long getWiggledExpirationTime() {
        return wiggledExpirationTime;
    }

    public void setWiggledExpirationTime(long anExpirationTime) {
        wiggledExpirationTime = anExpirationTime;
    }   
   
    /**
     * Gets whether this session is suspect (not trusted value)
     *
     * @return whether this session is suspect (not trusted value)
     */
    public boolean isSuspect() {
        return isSuspect.get();
    }
   
    /**
     * Sets whether this session is suspect (not trusted value)
     *
     * @param value whether this session is suspect (not trusted value)
     */
    public void setSuspect(boolean value) {
        isSuspect.set(value);
    }   

    /**
     * Checks whether this ServletTimer is dirty or not.
     *
     * @return true if this ServletTimer has been marked as dirty,
     * false otherwise
     */
    public boolean isDirty() {
        return isDirty;
    }

    /**
     * Marks this ServletTimer as dirty or non-dirty.
     *
     * @param isDirty The dirty flag
     */
    public void setDirty(boolean isDirty) {
        setDirty(isDirty, true);
    }
   
    /**
     * Marks this ServletTimer as dirty or non-dirty.
     *
     * @param isDirty The dirty flag
     * @param addToUnitOfWork should we add to unit of work
     */
    public void setDirty(boolean isDirty, boolean addToUnitOfWork) {
        this.isDirty = isDirty;

        if (isDirty == true && addToUnitOfWork) {
            addToUnitOfWork();
        }
    }   

    /**
     * Increments the version of this ServletTimer.
     */
    public void incrementVersion() {
        version.incrementAndGet();
    }

    /**
     * Gets the version of this ServletTimer.
     *
     * @return The version of this ServletTimer
     */
    public long getVersion() {
        return version.get();
    }

    /**
     * Sets the version of this ServletTimer.
     *
     * @value The new version of this ServletTimer
     */
    public void setVersion(long value) {
        version.getAndSet(value);
    }

    /**
     * is the ServletTimer persistent
     */
    public boolean isReplicated() {
        return isReplicated;
    }

    /**
     * this sets the persistent flag
     */
    public void setReplicated(boolean value) {
        isReplicated = value;
    }

    public ServletTimerExtraParams getExtraParameters() {
        return extraParams;
    }

    /**
     * Updates this ServletTimer with the given extra
     * parameters.
     *
     * @param extraParams The serialized ServletTimerExtraParams
     * @param deserializedExtraParams The deserialized ServletTimerExtraParams
     * used to update this
     * ServletTimer
     */
    public void update(byte[] extraParamsState, ServletTimerExtraParams deserializedExtraParams) {
       
        ServletTimerExtraParams extraParams = null;
       
        if(deserializedExtraParams != null) {
            extraParams = deserializedExtraParams;
        } else {
            if (extraParamsState != null) {
                try {
                    extraParams
                        = (ServletTimerExtraParams) ReplicationState.getObjectValue(extraParamsState, ((SipTransactionPersistentManager)getSipSessionManager()).isReplicationCompressionEnabled());
                } catch (Exception ex) {
                    LOGGER.log(Level.WARNING, "st_extraparams_deserialization_error", getId());
                    LOGGER.log(Level.WARNING, ex.getMessage(), ex);
                }                   
            }
        }
       
        if(extraParams != null) {
            setPFieldScheduledExecutionTime(extraParams.getExpirationTime(),
                                            false);
            this.setInternalLastAccessedTime(extraParams.getInternalLastAccessedTime());           
        }
    }

    /**
     * Validates this ServletTimer.
     */
    boolean validate(boolean loadDependencies) throws RemoteLockException {
        if (wasLockedOnRemoteInstance()) {
            throw new RemoteLockException(this +
                " has been locked on remote instance");
        }

        if (loadDependencies) {
            if (getPFieldAppSession() == null) {
                // ServletTimer is orphaned
                if (LOGGER.isLoggable(Level.FINE)) {
                    LOGGER.fine("ServletTimer " + getId() +
                    " has been orphaned");
                }
                getSipSessionManager().removeServletTimer(this);
                return false;
            }
        }
        return true;
    }

    boolean wasLockedOnRemoteInstance() {
        return wasLockedOnRemoteInstance;
    }

    /**
     * @serialData See serialized form version 1 in #readExternal(ObjectInput in)
     * 
     * @param oos the stream to write the object members
     * @throws IOException
     */
    public void writeExternal(ObjectOutput oos) throws IOException {
        oos.writeShort(serializedFormVersion);
        super.writeExternal(oos);
        oos.writeLong(version.get());
        oos.writeObject(currentOwnerInstanceName);
        oos.writeLong(wiggledExpirationTime); // possibly overridden by extraparams
        oos.writeLong(internalLastAccessedTime);
        // When doing normal replication, never mark the artifact as
        // foreground-locked. Foreground lock needs to be considered and
        // reflected in serialized representation only if artifact is being
        // served from active cache.
        if (isBeingReplicated) {
            oos.writeBoolean(false);
        } else {
            oos.writeBoolean(isForegroundLocked());
        }
    }


    /**
     * @serialData first field is an short and represents the serializedFormVersion.<br>
     * <h3>Data layout for serializedFormVersion = 2 follows</h3>
     *
     * <li>field is a <b>Externalizable</b> and represents superclass externalized data</li>
     * <li>field is a <b>Long</b> and represents the version for this instance</li>
     * <li>field is a <b>String</b> and represents the name of the owner instance when this instance was serialized</li>
     * <li>field is a <b>Long</b> and represents the wiggled expiration time for this instance</li>
     * <li>field is a <b>Long</b> and represents the internalLastAccessedTime field as absolute time</li>
     * <li>field is a <b>Boolean</b> and represents if the object is foreground locked</li>
     *
     * <h3>Data layout for serializedFormVersion = 1 follows</h3>
     *
     * <li>field is a <b>Externalizable</b> and represents superclass externalized data</li>
     * <li>field is a <b>String</b> and represents the name of the owner instance when this instance was serialized</li>
     * <li>field is a <b>Long</b> and represents the wiggled expiration time for this instance</li>
     * <li>field is a <b>Long</b> and represents the internalLastAccessedTime field as absolute time</li>
     * <li>field is a <b>Boolean</b> and represents if the object is foreground locked</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:
            super.readExternal(in);
            // Assumption is that version will be set from ReplicationUnit
            // immediately following deserialization
            version = new AtomicLong(-1);
            //we swap the currentOwner to become the previous owner instance
            previousOwnerInstanceName = (String) in.readObject();
            wiggledExpirationTime = in.readLong();
            internalLastAccessedTime = in.readLong();
            wasLockedOnRemoteInstance = in.readBoolean();
            currentOwnerInstanceName = ReplicationUtil.getInstanceName();
            extraParams = new ServletTimerExtraParams(this);
            isSuspect = new AtomicBoolean(false);
            break;
         case 2:
            super.readExternal(in);
            // Assumption is that version will be set from ReplicationUnit
            // immediately following deserialization
            version = new AtomicLong(in.readLong());
            //we swap the currentOwner to become the previous owner instance
            previousOwnerInstanceName = (String) in.readObject();
            wiggledExpirationTime = in.readLong();
            internalLastAccessedTime = in.readLong();
            wasLockedOnRemoteInstance = in.readBoolean();
            currentOwnerInstanceName = ReplicationUtil.getInstanceName();
            extraParams = new ServletTimerExtraParams(this);
            isSuspect = new AtomicBoolean(false);
            break;
        default:
            throw new IOException("Unable to deserialize into "
                    + this.getClass().getName()
                    + " with serialVersionUID = " + serialVersionUID
                    + " due to unknown serializedFormVersion of "
                    + readSerializedFormVersion);
        }
    }

    protected String getFullyQualifiedId() {
        return super.getFullyQualifiedId() + ":version:" + getVersion();
    }

    long getInternalLastAccessedTime() {
        return internalLastAccessedTime;
    }

    void setInternalLastAccessedTime(long value) {
        internalLastAccessedTime = value;
    }

    @Override
    protected long incrementAndGetPFieldNumInvocations() {
        long returnValue = super.incrementAndGetPFieldNumInvocations();
        setDirty(true);

        return returnValue;
    }

    @Override
    protected void setPFieldFirstExecution(long firstExecution) {
        super.setPFieldFirstExecution(firstExecution);
        setDirty(true);
    }

    @Override
    protected void setPFieldPersistent(boolean p) {
        super.setPFieldPersistent(p);
        setDirty(true);
    }

    @Override
    protected void setPFieldScheduledExecutionTime(long scheduledExecutionTime) {
        setPFieldScheduledExecutionTime(scheduledExecutionTime, true);
    }

    protected void setPFieldScheduledExecutionTime(long scheduledExecutionTime,
                                                   boolean setDirty) {
        super.setPFieldScheduledExecutionTime(scheduledExecutionTime);
        setWiggledExpirationTime(calculateWiggledTime(scheduledExecutionTime));
        if (setDirty) {
            setDirty(true);
        }
    }
   
    private long calculateWiggledTime(long expTime) {
        return ActivationHelper.calculateServletTimerTaskScheduleTime(expTime);
    }   

    /*
     * Processes a timeout event for this (active) ServletTimer upon
     * expiration.
     *
     * This method first checks if this ServletTimer has expired
     * on the correct (according to DCR) instance. If it hasn't, then
     * a loadadvisory is sent to the new rightful owner instance, which causes
     * this ServletTimer to migrate to it.
     *
     * An active ServletTimer might expire on the wrong instance, if the
     * cluster shape has changed, and the ServletTimer was not migrated to
     * the new rightful owner instance by active traffic.
     *
     * The rightful owner instance of a ServletTimer is derived from the
     * ServletTimer's parent SAS.
     */
    @Override
    public Object call() throws Exception {

        String myInstanceName = ReplicationUtil.getInstanceName();

        String actualOwnerName =
            SipApplicationSessionUtil.getActualServerInstance(sasId);
        if (actualOwnerName == null) {
            LOGGER.warning("in " + this.getClass().getName() + ">>call: " +
                "No rightful owner instance returned by " +
                "DataCentricUtil for SipApplicationSession " +
                "with id: " + sasId);
            return null;
        }

        if (myInstanceName.equals(actualOwnerName)) {
            // We have expired on the correct instance.
            return super.call();
        } else {
            // Issue a load advisory to the new rightful owner instance,
            // which will cause this ServletTimer to migrate to it
            SipTransactionPersistentManager mgr =
                (SipTransactionPersistentManager) getSipSessionManager();
            if (mgr != null) {
                mgr.sendLoadAdvisoryServletTimer(getId(), actualOwnerName);
            }
            return null;
        }       
    }
   
    /**
     * Gets the parent SAS id
     *
     * @return The id of the parent SipApplicationSession
     */
    public String getParentSASId() {
        return sasId;
    }
   
    /**
    * checks/adds this entity to unitOfWork
    */
    protected void addToUnitOfWork() {
        ReplicationUnitOfWork uow =
            ReplicationUnitOfWork.getThreadLocalUnitOfWork();
        if(uow != null) {
            uow.add(this);
        } else {
            throw new IllegalStateException("HAServletTimer>>addToUnitOfWork: unit of work missing");
        }
    }

    public void save() {
        // TODO consider introducing a synch object in ServletTimerImpl
        //
        PersistentSipSessionManagerBase sessionManager = (PersistentSipSessionManagerBase) getSipSessionManager();

        try {
            sessionManager.saveServletTimer(this);

            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.log(Level.FINE, "Saved ServletTimer: " + getId());
            }
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "st_save_error", getId());
            LOGGER.log(Level.WARNING, e.getMessage(), e);
        }
    }

    @Override
    public void cancel(boolean mayInterruptIfRunning) {
        super.cancel(mayInterruptIfRunning);
        // remove from unit-of-work due its already gone from SessionManager
        ReplicationUnitOfWork uow =
            ReplicationUnitOfWork.getThreadLocalUnitOfWork();
        if (uow != null) {
            uow.remove(this);
        }
    }

    /*
     * Passivates this ServletTimer.
     */
    public void passivate() {
        // Since we know there are no side effects to this we do not need an UOW

        // Remove from active cache
        SipTransactionPersistentManager mgr = (SipTransactionPersistentManager)
            getSipSessionManager();
        if (mgr != null) {
            mgr.removeServletTimerFromCache(this);
        }

        stop(true);
    }

    void setIsBeingReplicated(boolean isBeingReplicated) {
        this.isBeingReplicated = isBeingReplicated;
    }

    boolean isBeingReplicated() {
        return isBeingReplicated;
    }

    @Override
    protected String getIdForSerial() {
        return "";
    }

    void setId(String newId) {
        this.id = newId;
    }
}
TOP

Related Classes of org.jvnet.glassfish.comms.replication.sessmgmt.HAServletTimer

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.