/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.restcomm.media.control.mgcp.tx; import java.net.InetSocketAddress; import org.restcomm.media.concurrent.Lock; import org.restcomm.media.control.mgcp.MgcpProvider; import org.restcomm.media.control.mgcp.controller.CallManager; import org.restcomm.media.control.mgcp.controller.naming.NamingTree; import org.restcomm.media.scheduler.Clock; import org.restcomm.media.scheduler.Scheduler; /** * Implements pool of transactions. * * @author yulian oifa */ public class GlobalTransactionManager { //one byte block private GlobalTransactionManager[] subManager; //ports block private TransactionManager[] managers; //MGCP protocol provider protected MgcpProvider provider; //Scheduler private final Scheduler scheduler; private final Clock clock; //Endpoint naming tree private NamingTree namingService; private int poolSize; private Lock lock=new Lock(); public GlobalTransactionManager(Scheduler scheduler, Clock clock) { this.scheduler = scheduler; this.clock = clock; } /** * Associates endpoint naming service. * * @param namingService the endpoint naming service. */ public void setNamingService(NamingTree namingService) { this.namingService = namingService; } /** * Associates endpoint naming service. * * @param namingService the endpoint naming service. */ public void setPoolSize(int poolSize) { this.poolSize = poolSize; } /** * Gets the access to the scheduler. * * @return job scheduler. */ public Scheduler scheduler() { return scheduler; } /** * Provides access to the wall clock. * * @return time measured by wall clock. */ public long getTime() { return this.clock.getTime(); } /** * Assigns MGCP provider. * * @param provider mgcp provider instance */ public void setMgcpProvider(MgcpProvider provider) { this.provider = provider; } /** * Find active transaction with specified identifier. * * @param id the transaction identifier. * @return transaction object or null if does not exist. */ public Transaction find(InetSocketAddress source,int id) { return find(source.getAddress().getAddress(),source.getPort(),0,id); } private Transaction find(byte[] address,int port,int level,int id) { if(level==address.length-1) { checkPort(port-1); return managers[port-1].find(id); } int intIndex = ((int)address[level]) & 0xFF; checkAddress(intIndex); return subManager[intIndex].find(address, port, level+1, id); } public Transaction allocateNew(InetSocketAddress source,int id) { return allocateNew(source.getAddress().getAddress(),source.getPort(),0,id); } private Transaction allocateNew(byte[] address,int port,int level,int id) { if(level==address.length-1) { checkPort(port-1); // hrosa - look for transaction by tx number rather than unique id // Fixes issue MEDIA-20 Transaction old=managers[port-1].findByTransactionNumber(id); if (old == null) { return managers[port - 1].allocateNew(id); } else { return null; } } int intIndex = ((int)address[level]) & 0xFF; checkAddress(intIndex); return subManager[intIndex].allocateNew(address, port, level+1, id); } public TransactionManager createTransactionManager() { TransactionManager txManager = new TransactionManager(clock, scheduler, poolSize); txManager.setNamingService(namingService); txManager.setCallManager(new CallManager()); txManager.setMgcpProvider(provider); txManager.start(); return txManager; } private void checkPort(int portIndex) { if(managers==null) { try { lock.lock(); } catch(java.lang.InterruptedException e) { } if(managers==null) { managers=new TransactionManager[65536]; managers[portIndex]=createTransactionManager(); } lock.unlock(); } else if(managers[portIndex]==null) { try { lock.lock(); } catch(java.lang.InterruptedException e) { } if(managers[portIndex]==null) managers[portIndex]=createTransactionManager(); lock.unlock(); } } private void checkAddress(int intIndex) { if(subManager==null) { try { lock.lock(); } catch(java.lang.InterruptedException e) { } if(subManager==null) { subManager=new GlobalTransactionManager[256]; subManager[intIndex]=new GlobalTransactionManager(scheduler, clock); subManager[intIndex].setMgcpProvider(provider); subManager[intIndex].setNamingService(namingService); subManager[intIndex].setPoolSize(poolSize); } lock.unlock(); } else if(subManager[intIndex]==null) { try { lock.lock(); } catch(java.lang.InterruptedException e) { } if(subManager[intIndex]==null) { subManager[intIndex]=new GlobalTransactionManager(scheduler, clock); subManager[intIndex].setMgcpProvider(provider); subManager[intIndex].setNamingService(namingService); subManager[intIndex].setPoolSize(poolSize); } lock.unlock(); } } }