Package com.ericsson.ssa.sip.dialog

Source Code of com.ericsson.ssa.sip.dialog.DialogCleaner

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

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.sip.SipApplicationSession;

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

import com.ericsson.ssa.container.sim.ApplicationDispatcher;
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.RemoteLockRuntimeException;
import com.ericsson.ssa.sip.SipApplicationSessionImpl;
import com.ericsson.ssa.sip.SipSessionBase;
import com.ericsson.ssa.sip.SipSessionDialogImpl;
import com.ericsson.ssa.sip.SipSessionManagerBase;
import com.ericsson.ssa.sip.timer.GeneralTimer;
import com.ericsson.ssa.sip.timer.GeneralTimerListener;
import com.ericsson.ssa.sip.timer.TimerServiceImpl;
import com.ericsson.ssa.sip.transaction.TransactionManager;

/**
* This class handles cleanup of dialogs.
* - Triggers finalization of dialog life cycle activities
* - (future) handles removal of obsolete DialogSets and dialog structures that have been created for non-dialog requests.
*/
public class DialogCleaner {

    private static final long MAX_UOW_DURATION;
    private static final long CLEANING_INTERVAL;
    private static final long DS_SCAVENGE_INTERVAL;
    private static final long TR_SCAVENGE_INTERVAL;
    public static final long NO_DIALOG_TIMEOUT = 5000; // 5 second

    static {
        {
            long interval = 10; // In seconds
            try {
                interval = Integer.parseInt(System.getProperty("sipContainer.dc.dialogCleaningInterval", "" + interval));
            } catch (Throwable t) {
                // swallow...
            }
            CLEANING_INTERVAL = interval * 1000;
        }
        {
            long duration = (TransactionManager.getInstance().getTimerT1() * 64 + 10000)/1000; // In seconds
            try {
                duration = Integer.parseInt(System.getProperty("sipContainer.dc.maxUowActivityDuration", "" + duration));
            } catch (Throwable t) {
                // swallow...
            }
            MAX_UOW_DURATION = duration*1000;
        }
        {
            long dsi = 60; // In seconds
            try {
                dsi = Integer.parseInt(System.getProperty("sipContainer.dc.dsScavengeInterval", "" + dsi));
            } catch (Throwable t) {
                // swallow...
            }
            DS_SCAVENGE_INTERVAL = dsi*1000;
        }
        {
            long tsi = 60*10; // In seconds
            try {
                tsi = Integer.parseInt(System.getProperty("sipContainer.dc.transactionScavengeInterval", "" + tsi));
            } catch (Throwable t) {
                // swallow...
            }
            TR_SCAVENGE_INTERVAL = tsi*1000;
        }


    }
    private static volatile DialogCleaner instance;
    private static final Logger logger = LogUtil.SIP_LOGGER.getLogger();

    // Use a linked hash map to ensure FIFO order when iterating over it!
    private LinkedHashMap<Cleanable, CleanupRecord> supervisedLifeCycles = new LinkedHashMap<Cleanable, CleanupRecord>();
    private long nextDsScavenge;
    private long nextTrScavenge;
    private long nextDump;

    private class TimerListener implements GeneralTimerListener {

        public void timeout(GeneralTimer timer) {
            onTimeout();
            TimerServiceImpl.getInstance().createTimer(new TimerListener(), CLEANING_INTERVAL, null);
        }
    }

    private class CleanupRecord {

        private long expirationTime;
        private Cleanable cleanable;

        public CleanupRecord(Cleanable cleanable, long expirationTime) {
            this.cleanable = cleanable;
            this.expirationTime = expirationTime;
        }
    }

    private DialogCleaner() {
        TimerServiceImpl.getInstance().createTimer(new TimerListener(), CLEANING_INTERVAL, null);
    }

    /**
     * Gets the singleton instance.
     * @return
     */
    public static DialogCleaner getInstance() {
        if (instance == null) {
            synchronized (DialogCleaner.class) {
                if (instance == null)
                    instance = new DialogCleaner();       
            }
        }
        return instance;
    }
   
    /**
     * Sets the instance. Only for unit test purposes.
     * @param dc
     */
    static void setInstance(DialogCleaner dc) {
      instance = dc;
    }
    /**
     * Register the Cleanable for supervision. To trigger finalization of its current activity.
     * @param cleanable
     */
    synchronized public void registerForSupervision(Cleanable cleanable) {
        registerForSupervision(cleanable, MAX_UOW_DURATION);
    }
   
    /**
     * Register the Cleanable for supervision. To trigger finalization of its current activity.
     * @param cleanable
     * @param duration max duration before timeout in milliseconds
     */
    synchronized public void registerForSupervision(Cleanable cleanable, long duration) {
        if (logger.isLoggable(Level.FINEST)) {
            logger.log(Level.FINEST, "Register object for supervision: " + cleanable);
        }
        supervisedLifeCycles.put(cleanable, new CleanupRecord(cleanable, System.currentTimeMillis() + duration));
    }

    /**
     * Unregister the DialogLifeCycle from supervision.
     * @param dlc
     */
    synchronized void unregisterFromSupervision(DialogLifeCycle dlc) {
        if (logger.isLoggable(Level.FINEST)) {
            logger.log(Level.FINEST, "Un-register dialog for supervision: " + dlc.getDialogFragment().getFragmentId());
        }
        supervisedLifeCycles.remove(dlc);
    }

    private void onTimeout() {
        long now = System.currentTimeMillis();

        if (logger.isLoggable(Level.FINEST)) {
            StringBuffer sb = new StringBuffer();
            try {
                if (now > nextDump) {
                    nextDump = now + 180000; // Only log every 3rd minute.
                    logger.log(Level.FINEST, "Perform dialog clean-up");
                    logger.log(Level.FINEST, "Ongoing transactions in TransactionManager: " + TransactionManager.getInstance().getOngoingTransactions());
                    ApplicationDispatcher.getInstance().logActiveCaches();
                    Iterable<DialogFragment> dialogs = DialogFragmentManager.getInstance().getDialogs();
                    for (DialogFragment df : dialogs) {
                        sb.append("dlc={").append(df.getDialogLifeCycle().toString());
                        sb.append("; df.isValid=").append(df.isValid());
                        sb.append("; locks: df=").append(df.isForegroundLocked());
                        for (Iterator<PathNode> pnIt = df.getCaller2CalleePath(); pnIt.hasNext();) {
                            PathNode pn = pnIt.next();
                            sb.append("; ss (").append(pn.getSipSessionId()).append(")=");
                            try {
                                SipSessionBase ss;
                                if ((ss = pn.getSipSession()) != null) {
                                    sb.append(((SipSessionDialogImpl) ss).isForegroundLocked());
                                    SipApplicationSession sas;
                                    if ((sas = ss.getApplicationSession()) != null) {
                                        sb.append("; sas (").append(sas.getId()).append(")=").append(((SipApplicationSessionImpl) sas).isForegroundLocked());
                                    } else {
                                        sb.append("sas=null");
                                    }
                                } else {
                                    sb.append("null");
                                }
                            } catch (Throwable e) {
                                sb.append("exception at reading");
                            }
                        }
                        sb.append("}\n");
                    }
                }
            } catch (Throwable t) {
                logger.log(Level.FINEST, "Exception when logging active transaction, dialogs, sessions and timers; ignored");
            } finally {
                if (logger.isLoggable(Level.FINEST)) {
                    logger.log(Level.FINEST, "Dialogs: [" + sb.toString() + "]");
                }
            }
        }
       
        scavengeCleanables(now);
        scavengeDialogSets(now);
        scavengeTransactions(now);
    }

    private void scavengeDialogSets(long now) {
        if (now > nextDsScavenge) {
            nextDsScavenge = now + DS_SCAVENGE_INTERVAL;
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINE, "Do dialog set scavenging");
            }
            DialogSet.doScavenge();
        }
    }

    private void scavengeTransactions(long now) {
        if (now > nextTrScavenge) {
            nextTrScavenge = now + TR_SCAVENGE_INTERVAL;
            if (logger.isLoggable(Level.FINE)) {
                logger.log(Level.FINEST, "Do transaction scavenging");
            }
            TransactionManager.getInstance().doScavenge();
        }
    }

    private void scavengeCleanables(long now) {
        List<CleanupRecord> expired = new ArrayList<CleanupRecord>();
        synchronized (this) {
            for (Iterator<CleanupRecord> it = supervisedLifeCycles.values().iterator(); it.hasNext();) {
                CleanupRecord cleanupRecord = it.next();
                if (now >= cleanupRecord.expirationTime) {
                    it.remove();
                    expired.add(cleanupRecord);
                }
            }
        }
       
        for (Iterator<CleanupRecord> it = expired.iterator(); it.hasNext();) {
            CleanupRecord dlcRecord = it.next();
            try {
                dlcRecord.cleanable.doCleanup();
                if (logger.isLoggable(Level.FINEST)) {
                    logger.log(Level.FINEST, "Cleaned registered: " + dlcRecord.cleanable);
                }
            } catch (Throwable t) {
                if (logger.isLoggable(Level.WARNING)) {
                    logger.log(Level.WARNING, "Exception when cleaning up: " + dlcRecord.cleanable, t);
                }
            }
        }
    }
}
TOP

Related Classes of com.ericsson.ssa.sip.dialog.DialogCleaner

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.