Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2016, TeleStax Inc. and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* JBoss, Home of Professional Open Source
* Copyright 2007-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.jdiameter.server.impl.app.rf;
import static org.jdiameter.common.api.app.rf.ServerRfSessionState.IDLE;
import static org.jdiameter.common.api.app.rf.ServerRfSessionState.OPEN;
import java.io.Serializable;
import org.jdiameter.api.Answer;
import org.jdiameter.api.Avp;
import org.jdiameter.api.EventListener;
import org.jdiameter.api.IllegalDiameterStateException;
import org.jdiameter.api.InternalException;
import org.jdiameter.api.NetworkReqListener;
import org.jdiameter.api.OverloadException;
import org.jdiameter.api.Request;
import org.jdiameter.api.ResultCode;
import org.jdiameter.api.RouteException;
import org.jdiameter.api.app.AppSession;
import org.jdiameter.api.app.StateChangeListener;
import org.jdiameter.api.app.StateEvent;
import org.jdiameter.api.rf.ServerRfSession;
import org.jdiameter.api.rf.ServerRfSessionListener;
import org.jdiameter.api.rf.events.RfAccountingAnswer;
import org.jdiameter.api.rf.events.RfAccountingRequest;
import org.jdiameter.client.api.ISessionFactory;
import org.jdiameter.common.api.app.IAppSessionState;
import org.jdiameter.common.api.app.rf.IServerRfActionContext;
import org.jdiameter.common.api.app.rf.ServerRfSessionState;
import org.jdiameter.common.impl.app.rf.AppRfSessionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Server Accounting session implementation
*
* @author [email protected]
* @author Alexandre Mendonca
* @author Bartosz Baranowski
*/
@SuppressWarnings("all") //3rd party lib
public class ServerRfSessionImpl extends AppRfSessionImpl
implements EventListener, ServerRfSession, NetworkReqListener {
//FIXME: verify this FSM
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(ServerRfSessionImpl.class);
// Session State Handling ---------------------------------------------------
// Factories and Listeners --------------------------------------------------
protected transient IServerRfActionContext context;
protected transient ServerRfSessionListener listener;
// Ts Timer -----------------------------------------------------------------
protected static final String TIMER_NAME_TS = "TS";
protected IServerRfSessionData sessionData;
// Constructors -------------------------------------------------------------
public ServerRfSessionImpl(IServerRfSessionData sessionData, ISessionFactory sessionFactory,
ServerRfSessionListener serverSessionListener,
IServerRfActionContext serverContextListener, StateChangeListener stLst, long tsTimeout,
boolean stateless) {
// TODO Auto-generated constructor stub
super(sessionFactory, sessionData);
this.listener = serverSessionListener;
this.context = serverContextListener;
this.sessionData = sessionData;
this.sessionData.setTsTimeout(tsTimeout);
this.sessionData.setStateless(stateless);
super.addStateChangeNotification(stLst);
}
@Override
public void sendAccountAnswer(RfAccountingAnswer accountAnswer)
throws InternalException, IllegalStateException, RouteException, OverloadException {
try {
session.send(accountAnswer.getMessage());
/*
* TODO: Need to notify state change...
* if (isStateless() && isValid()) {
* session.release();
* }
*/
} catch (IllegalDiameterStateException e) {
throw new IllegalStateException(e);
}
}
@Override
public boolean isStateless() {
return this.sessionData.isStateless();
}
@SuppressWarnings("unchecked")
protected void setState(IAppSessionState newState) {
IAppSessionState oldState = this.sessionData.getServerRfSessionState();
this.sessionData.setServerRfSessionState((ServerRfSessionState) newState);
for (StateChangeListener i : stateListeners) {
i.stateChanged(this, (Enum) oldState, (Enum) newState);
}
}
@Override
public boolean handleEvent(StateEvent event) throws InternalException, OverloadException {
return isStateless() ? handleEventForStatelessMode(event) : handleEventForStatefulMode(event);
}
public boolean handleEventForStatelessMode(StateEvent event) throws InternalException, OverloadException {
try {
//this will handle RTRs as well, no need to alter.
final ServerRfSessionState state = this.sessionData.getServerRfSessionState();
switch (state) {
case IDLE: {
switch ((Event.Type) event.getType()) {
case RECEIVED_START_RECORD:
// Current State: IDLE
// Event: Accounting start request received, and successfully processed.
// Action: Send accounting start answer
// New State: IDLE
if (listener != null) {
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
// TODO: This is unnecessary state change: setState(IDLE);
break;
case RECEIVED_EVENT_RECORD:
// Current State: IDLE
// Event: Accounting event request received, and successfully processed.
// Action: Send accounting event answer
// New State: IDLE
if (listener != null) {
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
// FIXME: it is required, so we know it ends up again in IDLE!
setState(IDLE);
break;
case RECEIVED_INTERIM_RECORD:
// Current State: IDLE
// Event: Interim record received, and successfully processed.
// Action: Send accounting interim answer
// New State: IDLE
if (listener != null) {
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
// TODO: This is unnecessary state change: setState(IDLE);
break;
case RECEIVED_STOP_RECORD:
// Current State: IDLE
// Event: Accounting stop request received, and successfully processed
// Action: Send accounting stop answer
// New State: IDLE
if (listener != null) {
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
// TODO: This is unnecessary state change: setState(IDLE);
break;
default:
throw new IllegalStateException("Current state " + state + " action " + event.getType());
}
}
}
} catch (Exception e) {
logger.debug("Can not process event", e);
return false;
} finally {
// TODO: Since setState was removed, we are now using this to terminate. Correct?
// We can't release here, answer needs to be sent through. done at send.
// release();
}
return true;
}
public boolean handleEventForStatefulMode(StateEvent event) throws InternalException, OverloadException {
try {
if (((RfAccountingRequest) event.getData()).getMessage().isReTransmitted()) {
try {
setState(OPEN);
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
// FIXME: should we do this before passing to lst?
cancelTsTimer();
startTsTimer();
if (context != null) {
context.sessionTimerStarted(this, null);
}
} catch (Exception e) {
logger.debug("Can not handle event", e);
setState(IDLE);
}
return true;
} else {
final ServerRfSessionState state = this.sessionData.getServerRfSessionState();
switch (state) {
case IDLE: {
switch ((Event.Type) event.getType()) {
case RECEIVED_START_RECORD:
// Current State: IDLE
// Event: Accounting start request received, and successfully processed.
// Action: Send accounting start answer, Start Ts
// New State: OPEN
setState(OPEN);
if (listener != null) {
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
cancelTsTimer();
startTsTimer();
if (context != null) {
context.sessionTimerStarted(this, null);
}
} catch (Exception e) {
logger.debug("Can not handle event", e);
setState(IDLE);
}
}
break;
case RECEIVED_EVENT_RECORD:
// Current State: IDLE
// Event: Accounting event request received, and
// successfully processed.
// Action: Send accounting event answer
// New State: IDLE
if (listener != null) {
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
break;
}
break;
}
case OPEN: {
switch ((Event.Type) event.getType()) {
case RECEIVED_INTERIM_RECORD:
// Current State: OPEN
// Event: Interim record received, and successfully
// processed.
// Action: Send accounting interim answer, Restart Ts
// New State: OPEN
try {
listener.doRfAccountingRequestEvent(this, (RfAccountingRequest) event.getData());
cancelTsTimer();
startTsTimer();
if (context != null) {
context.sessionTimerStarted(this, null);
}
} catch (Exception e) {
logger.debug("Can not handle event", e);
setState(IDLE);
}
break;
case RECEIVED_STOP_RECORD:
// Current State: OPEN
// Event: Accounting stop request received, and
// successfully
// processed
// Action: Send accounting stop answer, Stop Ts
// New State: IDLE
setState(IDLE);
try {
listener.doRfAccountingRequestEvent(this,
(RfAccountingRequest) event.getData());
cancelTsTimer();
if (context != null) {
context.sessionTimerCanceled(this, null);
}
} catch (Exception e) {
logger.debug("Can not handle event", e);
setState(IDLE);
}
break;
}
break;
}
}
}
} catch (Exception e) {
logger.debug("Can not process event", e);
return false;
}
return true;
}
private void startTsTimer() {
// return scheduler.schedule(new Runnable() {
// public void run() {
// logger.debug("Ts timer expired");
// if (context != null) {
// try {
// context.sessionTimeoutElapses(ServerRfSessionImpl.this);
// }
// catch (InternalException e) {
// logger.debug("Failure on processing expired Ts", e);
// }
// }
// setState(IDLE);
// }
// }, tsTimeout, TimeUnit.MILLISECONDS);
try {
sendAndStateLock.lock();
if (sessionData.getTsTimeout() > 0) {
this.sessionData.setTsTimerId(
super.timerFacility.schedule(getSessionId(), TIMER_NAME_TS, this.sessionData.getTsTimeout()));
}
} finally {
sendAndStateLock.unlock();
}
}
private void cancelTsTimer() {
try {
sendAndStateLock.lock();
final Serializable tsTimerId = this.sessionData.getTsTimerId();
if (tsTimerId != null) {
super.timerFacility.cancel(tsTimerId);
this.sessionData.setTsTimerId(null);
}
} finally {
sendAndStateLock.unlock();
}
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.common.impl.app.AppSessionImpl#onTimer(java.lang.String)
*/
@Override
public void onTimer(String timerName) {
if (timerName.equals(IDLE_SESSION_TIMER_NAME)) {
checkIdleAppSession();
} else if (timerName.equals(TIMER_NAME_TS)) {
if (context != null) {
try {
context.sessionTimeoutElapses(ServerRfSessionImpl.this);
} catch (InternalException e) {
logger.debug("Failure on processing expired Ts", e);
}
}
setState(IDLE);
} else {
logger.warn("Received an unknown timer '{}' for Session-ID '{}'", timerName, getSessionId());
}
}
protected Answer createStopAnswer(Request request) {
Answer answer = request.createAnswer(ResultCode.SUCCESS);
answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 4);
answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
return answer;
}
protected Answer createInterimAnswer(Request request) {
Answer answer = request.createAnswer(ResultCode.SUCCESS);
answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 3);
answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
return answer;
}
protected Answer createEventAnswer(Request request) {
Answer answer = request.createAnswer(ResultCode.SUCCESS);
answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 2);
answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
return answer;
}
protected Answer createStartAnswer(Request request) {
Answer answer = request.createAnswer(ResultCode.SUCCESS);
answer.getAvps().addAvp(Avp.ACC_RECORD_TYPE, 1);
answer.getAvps().addAvp(request.getAvps().getAvp(Avp.ACC_RECORD_NUMBER));
return answer;
}
@Override
@SuppressWarnings("unchecked")
public E getState(Class eClass) {
return eClass == ServerRfSessionState.class ? (E) this.sessionData.getServerRfSessionState() : null;
}
@Override
public Answer processRequest(Request request) {
if (request.getCommandCode() == RfAccountingRequest.code) {
try {
sendAndStateLock.lock();
handleEvent(new Event(createAccountRequest(request)));
} catch (Exception e) {
logger.debug("Can not handle event", e);
} finally {
sendAndStateLock.unlock();
}
} else {
try {
listener.doOtherEvent(this, createAccountRequest(request), null);
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
return null;
}
@Override
public void receivedSuccessMessage(Request request, Answer answer) {
if (request.getCommandCode() == RfAccountingRequest.code) {
try {
sendAndStateLock.lock();
handleEvent(new Event(createAccountRequest(request)));
} catch (Exception e) {
logger.debug("Can not handle event", e);
} finally {
sendAndStateLock.unlock();
}
try {
listener.doRfAccountingRequestEvent(this, createAccountRequest(request));
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
} else {
try {
listener.doOtherEvent(this, createAccountRequest(request), createAccountAnswer(answer));
} catch (Exception e) {
logger.debug("Can not handle event", e);
}
}
}
@Override
public void timeoutExpired(Request request) {
// FIXME: alexandre: We don't do anything here... are we even getting this on server?
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.common.impl.app.AppSessionImpl#isReplicable()
*/
@Override
public boolean isReplicable() {
return true;
}
@Override
public void release() {
if (isValid()) {
try {
sendAndStateLock.lock();
//TODO: cancel timer?
super.release();
} catch (Exception e) {
logger.debug("Failed to release session", e);
} finally {
sendAndStateLock.unlock();
}
} else {
logger.debug("Trying to release an already invalid session, with Session ID '{}'", getSessionId());
}
}
}