Package org.jvnet.glassfish.comms.replication.dialogmgmt

Source Code of org.jvnet.glassfish.comms.replication.dialogmgmt.HADialogFragment

/*
* 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.dialogmgmt;

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

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

import javax.servlet.sip.Address;
import com.ericsson.ssa.sip.DialogFragment;
import com.ericsson.ssa.sip.DialogFragmentManager;
import com.ericsson.ssa.sip.DialogSet;
import com.ericsson.ssa.sip.PathNode;
import com.ericsson.ssa.sip.PersistentDialogFragmentManager;
import com.ericsson.ssa.sip.RemoteLockException;
import com.ericsson.ssa.sip.SipSessionImplBase;
import com.ericsson.ssa.sip.SipSessionManager;
import com.ericsson.ssa.sip.persistence.ReplicationUnitOfWork;
import com.sun.appserv.ha.uow.ReplicableEntity;
import com.sun.enterprise.ee.web.sessmgmt.ReplicationState;
import com.sun.enterprise.ee.web.sessmgmt.ReplicationUtil;

import javax.servlet.sip.Address;

/**
* Based on conversation with Larry and Jan on 11/7, the logic of this class is being considered
* to be moved into sipstack. All DialogFragments must be capable of being either inmemory or replicated.
* All members of DialogFragment must be replicable for dialogfragment to be replicable.  Need to
* discuss this on Sailfin replication discussion alias.
*
* For now, keep logic here till design agreed upon with Sailfin group.
*
* @author jf39279
*/
public class HADialogFragment extends DialogFragment implements ReplicableEntity {

    // XXX make configurable?
    private static final long DELTA = (10 * 1000); // 10 secs

    private static final long serialVersionUID = 1L;

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

    private transient boolean isDirty = false;

    // The version of this DialogFragment
    protected transient AtomicLong version = new AtomicLong(-1);
    private transient boolean isBeingReplicated = false;
    protected transient boolean isReplicated = false;
    private transient DialogFragmentExtraParams extraParams;
    private transient String previousOwnerInstanceName;
    private transient String currentOwnerInstanceName;
    private transient AtomicBoolean isSuspect
        = new AtomicBoolean(false);   
    private transient boolean wasLockedOnRemoteInstance = false;
    private transient long expirationTime = 0L;
    private transient long internalLastAccessedTime;
   
    /**
     * Constructor.
     * @param ds  dialog set
     */
    public HADialogFragment(DialogSet ds) {
        super(ds);
        extraParams = new DialogFragmentExtraParams(this);
        currentOwnerInstanceName = ReplicationUtil.getInstanceName();
    }

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

    public String getId() {
        return getDialogId();
    }

    @Override
    protected void initDialogLifeCycle() {
        super.initDialogLifeCycle();
    }

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

    /**
     * Gets the name of the instance.that currently owns this DialogFragment.
     *
     * @return The name of the instance that currently owns this DialogFragment
     */
    public String getCurrentOwnerInstanceName() {
        if (currentOwnerInstanceName == null) {
            return ReplicationUtil.getInstanceName();
        } else {
            return currentOwnerInstanceName;
        }
    }
   
    /**
     * Gets whether this session is suspect (not trusted value)
     *
     * @return whether this session is suspect (not trusted value)
     */
    public boolean isSuspect() {
        if (isSuspect != null) {
            return isSuspect.get();
        } else {
            return false;
        }
    }
   
    /**
     * Sets whether this session is suspect (not trusted value)
     *
     * @param value whether this session is suspect (not trusted value)
     */
    public void setSuspect(boolean value) {
        if (isSuspect != null) {
            isSuspect.set(value);
            if(!value) {
                ((ReplicationDialogFragmentManager)DialogFragmentManager.getInstance()).
                        removeExpatListElement(getId());               
            }
        }
    }   

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

    /**
     * Marks this dialog fragment as dirty or non-dirty.
     *
     * @param isDirty The dirty flag
     */
    public void setDirty(boolean isDirty) {
        setDirty(isDirty, true);
    }
   
    /**
     * Marks this dialog fragment 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 SipApplicationSession.
     */
    public void incrementVersion() {
        version.incrementAndGet();
    }

    /**
     * Gets the version of this SipApplicationSession.
     *
     * @return The version of this SipApplicationSession
     */
    public long getVersion() {
        if (version != null) {
            return version.get();
        } else {
            return -1L;
        }
    }

    /**
     * Sets the version of this SipApplicationSession.
     *
     * @value The new version of this SipApplicationSession
     */
    public void setVersion(long value) {
        if (version != null) {
            version.getAndSet(value);
        }
    }

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

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

    public DialogFragmentExtraParams getExtraParameters() {
        return extraParams;
    }

    /**
     * Updates this DialogFragment with the given extra
     * parameters.
     *
     * @param extraParams The serialized DialogFragmentExtraParams
     * @param deserializedExtraParams The deserialized DialogFragmentExtraParams
     * used to update this
     * DialogFragment
     */
    public void update(byte[] extraParamsState, DialogFragmentExtraParams deserializedExtraParams) {
       
        DialogFragmentExtraParams extraParams = null;
       
        if(deserializedExtraParams != null) {
            extraParams = deserializedExtraParams;
        } else {
            if (extraParamsState != null) {
                try {
                    extraParams
                        = (DialogFragmentExtraParams) ReplicationState.getObjectValue(extraParamsState, ((ReplicationDialogFragmentManager)DialogFragmentManager.getInstance()).isReplicationCompressionEnabled());
                } catch (Exception ex) {
                    LogUtil.SSR_LOGGER.getLogger().log(Level.WARNING, "df_extraparams_deserialization_error", getFragmentId());
                    LogUtil.SSR_LOGGER.getLogger().log(Level.WARNING, ex.getMessage(), ex);
                }                   
            }
        }
       
        if(extraParams != null) {
            setExpirationTime(extraParams.getExpirationTime(), false);
        }
       
    }

    /**
     * Validates this DialogFragment to see if it or any of its SipSessions
     * (and their associated SipApplicationSessions) fail to be loaded
     * (e.g., because they have been locked on a remote instance).
     *
     * This method does the following:
     * - Try to load each of the DialogFragment's SipSessions.
     * - As part of loading a SipSession, the associated SAS is also loaded.
     *   If a SipSession or its SAS fail to be loaded (e.g., because
     *   they are locked on a remote instance), this DialogFragment also
     *   will not be loaded, and this method will throw a RemoteLockException,
     * - It is safe for any SipSession and associated SAS that were
     *   successfully loaded and swapped into the active cache to remain in
     *   the active cache, i.e., there is no need to undo their loading.
     */
    void validate() throws RemoteLockException {
        if (wasLockedOnRemoteInstance()) {
            throw new RemoteLockException(this +
                    " has been locked on remote instance");
        }

        Iterator<PathNode> iter = getCaller2CalleePath();

        if (iter != null) {
            while (iter.hasNext()) {
                PathNode node = iter.next();
                SipSessionManager mgr = node.getSipSessionManager();
                // The following may throw RemoteLockException
                if (mgr != null) {
                    mgr.findSipSession(node.getSipSessionId());
                }
            }
        }
    }

    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);
        if (currentOwnerInstanceName == null) {
            oos.writeObject(ReplicationUtil.getInstanceName());
        } else {
            oos.writeObject(currentOwnerInstanceName);
        }
        oos.writeLong(expirationTime);
        // 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 = 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 expirationTime 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();
            currentOwnerInstanceName = ReplicationUtil.getInstanceName();
            expirationTime = in.readLong();
            wasLockedOnRemoteInstance = in.readBoolean();
            extraParams = new DialogFragmentExtraParams(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);
        }
    }

    public String toString() {
        return "id:" + getDialogId() + ":version:" + getVersion();
    }

    /**
     * Updates the expiration time of this DialogFragment with that of the
     * given SipSession if necessary
     */
    public void setExpirationTime(SipSessionImplBase ss) {
        if (ss == null) {
            return;
        }
        long ssExpTime = ss.getExpirationTime();
        if (ssExpTime <= 0) {
            // infinite case
            setExpirationTime(-1L);
        } else {
            setExpirationTime(ssExpTime);
        }
    }

    // XXX should I use the PField naming convention here as well?
    // this is only exposed in the HA version at the moment
    public void setExpirationTime(long expTime) {
        setExpirationTime(expTime, true);
    }

    private void setExpirationTime(long expTime,
                                   boolean addToUnitOfWork) {
        // This is never called with expTime == 0.
        // Update the expirationTime of this DialogFragment it becomes
        // infinite or greater.
        // Otherwise, don't even bother adding this DialogFragment to
        // the UOW.
        if (expTime != expirationTime &&
                (expTime == -1L || expTime > expirationTime)) {
            expirationTime = expTime;
            if (addToUnitOfWork) {
                // we must not set the dirty flag
                // since this is an extraParam field
                // for this we disabled the consistency check
                // as we know this is invoked in the context of the
                // SASes UOW
                addToUnitOfWork(false);
            }
        }
    }

    public long getExpirationTime() {
        return expirationTime;
    }
   
    public void setInternalLastAccessedTime(long internalLastAccessedTime) {
        this.internalLastAccessedTime = internalLastAccessedTime;
    }
   
    public long getInternalLastAccessedTime() {
        return internalLastAccessedTime;
    }

    /**
     * Confirms this DialogFragment, and also derives its expirationTime
     * from that of its children.
     */
    @Override
    public void setConfirmed() {

        Iterator<PathNode> iter = getCallee2CallerPath();
        if (iter != null) {
            while (iter.hasNext()) {
                setExpirationTime((SipSessionImplBase) iter.next().getSipSession());
            }
        }

        super.setConfirmed();
        setDirty(true);

        if (!isReplicable()) {
            // Null out any instance variables that are not used in
            // non-replicating mode, to save memory
            extraParams = null;
            version = null;
            isSuspect = null;
            currentOwnerInstanceName = null;
        }
    }

    /**
     * checks/adds this entity to unitOfWork
     * By default check the consistency
     */
    protected void addToUnitOfWork() {
        addToUnitOfWork(true);
    }

    /**
     * checks/adds this entity to unitOfWork
     * @param checkConsistency whether to check if the uow belongs to the df
     */
    protected void addToUnitOfWork(boolean checkConsistency) {
        if (isConfirmed() && isReplicable()) {
            if (checkConsistency) {
                getDialogLifeCycle().checkUnitOfWork();
            }
            ReplicationUnitOfWork uow
                = ReplicationUnitOfWork.getThreadLocalUnitOfWork();
            if(uow != null) {
                uow.add(this);
            } else {
                throw new IllegalStateException("HADialogFragment>>addToUnitOfWork: unit of work missing");
            }           
        }
    }

    public void save() {
      if (!isValid()) return;
     
        PersistentDialogFragmentManager dialogFragmentManager = (PersistentDialogFragmentManager) DialogFragmentManager.getInstance();

        synchronized (validLock) { // TODO rename name of lock???

            try {
                dialogFragmentManager.saveDialogFragment(this);
                if (LogUtil.SSR_LOGGER.getLogger().isLoggable(Level.FINE)) {
                    LogUtil.SSR_LOGGER.getLogger().log(Level.FINE,
                            "Saved DF: " + getFragmentId());
                }
            } catch (IOException e) {
                LogUtil.SSR_LOGGER.getLogger().log(Level.WARNING, "df_save_error", getFragmentId());
                LogUtil.SSR_LOGGER.getLogger().log(Level.WARNING, e.getMessage(), e);
            }
        }
    }

    @Override
    public void invalidate(boolean hasTimedOut) {
        super.invalidate(hasTimedOut);

        // remove from unit-of-work due its already gone from SessionManager
        if (isConfirmed() && isReplicable()) {
            ReplicationUnitOfWork uow
                = ReplicationUnitOfWork.getThreadLocalUnitOfWork();
            if(uow != null) {
                uow.remove(this);
            }
        }
    }
   
    /**
    * Any changes made to 'from' address during the mid-dialog
    * should cause the replication of DialogFragment.
    */
    @Override
    public void setFrom(Address from) {
        if(isConfirmed()) {
            setDirty(true, true);
        }
        super.setFrom(from);
    }

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

    boolean isBeingReplicated() {
        return isBeingReplicated;
    }
}
TOP

Related Classes of org.jvnet.glassfish.comms.replication.dialogmgmt.HADialogFragment

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.