Package org.jvnet.glassfish.comms.clb.core.sip

Source Code of org.jvnet.glassfish.comms.clb.core.sip.SipClientToClbFEMapper

/*
* 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.clb.core.sip;

import javax.servlet.sip.Address;
import javax.servlet.sip.ServletParseException;
import javax.servlet.sip.URI;
import javax.servlet.sip.SipURI;

import com.ericsson.ssa.sip.Header;
import com.ericsson.ssa.sip.SipFactoryImpl;
import com.ericsson.ssa.sip.SipServletRequestImpl;
import com.ericsson.ssa.sip.SipServletResponseImpl;
import com.ericsson.ssa.sip.SipURIImpl;
import com.ericsson.ssa.sip.ViaImpl;
import com.ericsson.ssa.sip.dns.SipTransports;
import com.ericsson.ssa.sip.dns.TargetTuple;
import com.ericsson.ssa.sip.dns.TargetResolver;

import com.sun.enterprise.Switch;
import java.util.ListIterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.sip.SipSession;
import org.jvnet.glassfish.comms.clb.core.CLBConstants;
import org.jvnet.glassfish.comms.clb.core.util.LoadbalancerUtil;
import org.jvnet.glassfish.comms.util.LogUtil;

/**
*
* @author kshitiz
*/
public class SipClientToClbFEMapper {

    private static final Logger logger = LogUtil.CLB_LOGGER.getLogger();
    private ConcurrentHashMap<String, Address> feAddrMapForRegisterReq;
    private ConcurrentHashMap<String, TimerTask>
            feAddrCleanupTasksMap;
    private boolean reuseConnections;
    private static final SipClientToClbFEMapper instance =
            new SipClientToClbFEMapper();
    private static final Timer timer = Switch.getSwitch().getTimer();

    private SipClientToClbFEMapper() {
        //Only set at time of instance creation
        //This value is not dynamically reconfigurable
        reuseConnections = LoadbalancerUtil.isReuseClientFEConnection();
        if (reuseConnections) {
            feAddrMapForRegisterReq = new ConcurrentHashMap<String, Address>();
            feAddrCleanupTasksMap = new ConcurrentHashMap<String, TimerTask>();
        }
    }

    public static SipClientToClbFEMapper getInstance() {
        return instance;
    }

    /**
     * Create mapping of FE address for client. This will only be done for
     * REGISTER request OR dialog creating request
     *
     * @param response response being send to client
     *
     * @throws org.jvnet.glassfish.comms.clb.core.sip.SipRoutingException
     */
    public void createFEAddressMapping(SipServletResponseImpl response)
            throws SipRoutingException {
        if (!reuseConnections) {
            return;
        }

        SipServletRequestImpl request = response.getRequestImpl();
        if (request == null) {
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("There is no request associated with response");
            }
            return;
        }

        if (!request.getRemote().getProtocol().equals(SipTransports.TCP_PROT)) {
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("Protocol used in not TCP");
            }
            return;
        }

        String method = request.getMethod();
        SipSession session = null;
        boolean isRegisterMethod = false;
        if (method.equals("REGISTER")) {
            isRegisterMethod = true;
        } else {
            //only consider dialog creating requests
            if (SipFactoryImpl.isDialogCreational(method)) {
                //Create mapping only if sip session exists
                session = request.getSession(false);
                if (session == null || !session.isValid()) {
                    if (logger.isLoggable(Level.FINER)) {
                        logger.finer("Session is null or invalid");
                    }
                    return;
                }
            }
        }

        Address contactAddress = null;
        try {
            contactAddress = request.getAddressHeader(Header.CONTACT);
        } catch (ServletParseException ex) {
            throw new SipRoutingException("Unable to get Contact header", ex);
        }

        if (isRegisterMethod && contactAddress.getExpires() == 0) {
            return;
        }

        String contact = null;
        if (contactAddress.getURI().isSipURI()) {
            contact = createContact((SipURI) contactAddress.getURI());
        } else {
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("Contact address is not sip uri");
            }
            return;
        }
       
        Header viaHeader = request.getRawHeader(Header.VIA);
        ListIterator<String> viaHeaderIter = viaHeader.getValues();
        ViaImpl firstViaHeader = new ViaImpl(viaHeaderIter.next());
        String felbParam =
                firstViaHeader.getParameter(CLBConstants.FE_LB_PARAM);
        //Request is not proxied, there will be no Path header added by FE
        if (felbParam == null) {
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("felb param is null");
            }
            return;
        }

        Address feAddress = createSipAddress(
                firstViaHeader.getHost(), firstViaHeader.getPort());

        int statusCode = response.getStatus();
        if ( statusCode >= 200 && statusCode < 300) {
            if (isRegisterMethod) {
                String expires = request.getHeader(Header.EXPIRES);
                if(expires == null) {
                    return;
               
                }
                storeFEAddrForRegisterReq(contact, feAddress,
                        Integer.parseInt(expires));
            } else {
                session.setAttribute(CLBConstants.CLB_FE_ADDRESS, feAddress);
            }
        }
    }

    public void removeFEAddressMapping(SipServletRequestImpl request) throws SipRoutingException {
        if (!reuseConnections) {
            return;
        }
       
        String method = request.getMethod();
        if (!method.equals("REGISTER")) {
            return;
        }
       
        Address contactAddress = null;
        try {
            contactAddress = request.getAddressHeader(Header.CONTACT);
        } catch (ServletParseException ex) {
            throw new SipRoutingException("Unable to get Contact header", ex);
        }

        if(contactAddress.getExpires() > 0){
            return;
        }
       
        String contact = null;
        if (contactAddress.getURI().isSipURI()) {
            contact = createContact((SipURI) contactAddress.getURI());
        } else {
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("Contact address is not sip uri");
            }
            return;
        }
       
        removeFEAddrForRegisterReq(contact);
    }

    private void removeFEAddrForRegisterReq(String contact) {
        if (logger.isLoggable(Level.FINER)) {
                logger.finer("Removing mapping from feAddrMapForRegisterReq for contact : " + contact);
        }
        feAddrMapForRegisterReq.remove(contact);
        if (logger.isLoggable(Level.FINER)) {
                logger.finer("feAddrMapForRegisterReq : " + feAddrMapForRegisterReq);
        }
        TimerTask task = feAddrCleanupTasksMap.remove(contact);
        if(task != null && task.cancel()){
            timer.purge();
        }
    }

    private void storeFEAddrForRegisterReq(String contact, Address pathValue,
            int expires) {
        if (logger.isLoggable(Level.FINER)) {
                logger.finer("Adding path mapping to feAddrMapForRegisterReq for contact : " + contact + " with value : " + pathValue);
        }
        if (contact == null || pathValue == null) {
            return;
        }
        TimerTask task = feAddrCleanupTasksMap.remove(contact);
        if(task != null && task.cancel()){
            timer.purge();
        }       
        feAddrMapForRegisterReq.put(contact, pathValue);
        if (logger.isLoggable(Level.FINER)) {
                logger.finer("feAddrMapForRegisterReq : " + feAddrMapForRegisterReq);
        }
        if (logger.isLoggable(Level.FINER)) {
                logger.finer("Adding timer task with expires of " + expires + "seconds");
        }
        task = new FEAddressMapCleanupTask(contact);
        timer.schedule(task, expires * 1000);
        feAddrCleanupTasksMap.put(contact, task);       
    }

    /**
     * Push route containing FE address if a mapping exists for request uri
     *
     * @param request Sip request
     * @param bindHostName Bind host name
     * @param bindPort Bind port
     * @throws org.jvnet.glassfish.comms.clb.core.sip.SipRoutingException
     */
    public void pushRouteHeader(SipServletRequestImpl request,
            String bindHostName, int bindPort) throws SipRoutingException {
        if (!reuseConnections) {
            return;
        }

        URI requestUri = request.getRequestURI();
        String contact = null;
        if (requestUri.isSipURI()) {
            SipURI sipUri = (SipURI) requestUri;
            contact = createContact(sipUri);
        } else {
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("Contact address is not sip uri");
            }
            return;
        }

        Address storedPathValue = feAddrMapForRegisterReq.get(contact);
        if (storedPathValue == null) {
            SipSession session = request.getSession(false);
            if (session == null || !session.isValid()) {
                if (logger.isLoggable(Level.FINER)) {
                    logger.finer("Session is null or invalid");
                }
                return;
            }
            storedPathValue = (Address) session.getAttribute(
                    CLBConstants.CLB_FE_ADDRESS);
        }
        if (storedPathValue != null) {
            request.pushRoute(storedPathValue);
            TargetTuple tt = null;
            try {
                tt = TargetResolver.getInstance().resolveRequest(request, request.getContentLength());
            } catch (Exception ex) {
                throw new SipRoutingException("Unable to resolve address for request", ex);
            }
            tt.setBindIp(bindHostName);
            tt.setBindPort(bindPort);
            tt.setCLBEndpoint(true);
            request.setResolvedRemote(tt);
            if (logger.isLoggable(Level.FINER)) {
                logger.finer("Request after adding FE as route header :\n" + request);
            }
        }
    }

    private String createContact(SipURI sipUri) {
        String contact;
        contact = sipUri.getUser() + "@" + sipUri.getHost() + ":" + sipUri.getPort();
        return contact;
    }

    private Address createSipAddress(String hostName, int port) {
        SipURI feSipUri = new SipURIImpl();
        feSipUri.setHost(hostName);
        feSipUri.setPort(port);
        feSipUri.setLrParam(true);
        feSipUri.setParameter(CLBConstants.FE_LB_PARAM, "TRUE");
        Address feAddress = SipFactoryImpl.getInstance().createAddress(feSipUri);
        return feAddress;
    }
   
    class FEAddressMapCleanupTask extends TimerTask{
       
        String contact;

        public FEAddressMapCleanupTask(String contact) {
            this.contact = contact;                   
        }
       
        @Override
        public void run() {
            removeFEAddrForRegisterReq(contact);
            feAddrCleanupTasksMap.remove(contact);
        }
       
    }
}
TOP

Related Classes of org.jvnet.glassfish.comms.clb.core.sip.SipClientToClbFEMapper

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.