/* * Copyright (c) 2006 jDiameter. * https://jdiameter.dev.java.net/ * * License: Lesser General Public License (LGPL) * * e-mail: erick.svenson@yahoo.com * */ package org.jdiameter.server.impl.app.acc; import static org.jdiameter.common.api.app.acc.ServerAccSessionState.IDLE; import static org.jdiameter.common.api.app.acc.ServerAccSessionState.OPEN; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; 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.Session; import org.jdiameter.api.acc.ServerAccSession; import org.jdiameter.api.acc.ServerAccSessionListener; import org.jdiameter.api.acc.events.AccountAnswer; import org.jdiameter.api.acc.events.AccountRequest; import org.jdiameter.api.app.StateChangeListener; import org.jdiameter.api.app.StateEvent; import org.jdiameter.common.api.app.IAppSessionState; import org.jdiameter.common.api.app.acc.IServerAccActionContext; import org.jdiameter.common.api.app.acc.ServerAccSessionState; import org.jdiameter.common.impl.app.acc.AccountRequestImpl; import org.jdiameter.common.impl.app.acc.AppAccSessionImpl; public class ServerAccSessionImpl extends AppAccSessionImpl implements EventListener<Request, Answer>, ServerAccSession, NetworkReqListener { protected ServerAccSessionState state = ServerAccSessionState.IDLE; protected IServerAccActionContext context; protected long tsTimeout; protected ScheduledFuture tsTask; protected ServerAccSessionListener listener; protected boolean stateless = false; //protected Logger logger =Logger.getLogger(ServerAccSessionImpl.class.getCanonicalName()); public ServerAccSessionImpl(Session session, Request initialRequest, ServerAccSessionListener listener, long tsTimeout, boolean stateless, StateChangeListener... scListeners) { if (session == null) throw new IllegalArgumentException("Session can not be null"); if (listener == null) throw new IllegalArgumentException("Session listener can not be null"); this.session = session; this.listener = listener; if (this.listener instanceof IServerAccActionContext) { context = (IServerAccActionContext) this.listener; } this.tsTimeout = tsTimeout; this.stateless = stateless; this.session.setRequestListener(this); for (StateChangeListener l : scListeners) addStateChangeNotification(l); //processRequest(initialRequest); } public void sendAccountAnswer(AccountAnswer accountAnswer) throws InternalException, IllegalStateException, RouteException, OverloadException { try { session.send(accountAnswer.getMessage()); } catch (IllegalDiameterStateException e) { throw new IllegalStateException(e); } } public boolean isStateless() { return stateless; } protected void setState(IAppSessionState newState) { IAppSessionState oldState = state; state = (ServerAccSessionState) newState; for (StateChangeListener i : stateListeners) { i.stateChanged((Enum) oldState, (Enum) newState); } } public boolean handleEvent(StateEvent event) throws InternalException, OverloadException { return stateless ? handleEventForStatelesMode(event) : handleEventForStatefullMode(event); } public boolean handleEventForStatelesMode(StateEvent event) throws InternalException, OverloadException { try { switch (state) { // Idle ========== case IDLE: { switch ((Event.Type) event.getType()) { case RECIVED_START_RECORD: if (listener != null) try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); } catch (Exception e) { logger.debug(e.getMessage(), e); } setState(IDLE); break; case RECIVED_EVENT_RECORD: if (listener != null) try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); } catch (Exception e) { logger.debug(e.getMessage(), e); } setState(IDLE); break; case RECIVED_INTERIM_RECORD: if (listener != null) try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); } catch (Exception e) { logger.debug(e.getMessage(), e); } setState(IDLE); break; case RECIVED_STOP_RECORD: if (listener != null) try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); } catch (Exception e) { logger.debug(e.getMessage(), e); } setState(IDLE); break; default: throw new IllegalStateException("Current state " + state + " action " + event.getType()); } } } } catch (Exception e) { logger.debug(e.getMessage(), e); return false; } return true; } public boolean handleEventForStatefullMode(StateEvent event) throws InternalException, OverloadException { try { switch (state) { // Idle ========== case IDLE: { switch ((Event.Type) event.getType()) { case RECIVED_START_RECORD: if (listener != null) { try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); tsTask = runTsTimer(); if (context != null) context.sessionTimerStarted(this, tsTask); setState(OPEN); } catch (Exception e) { logger.debug(e.getMessage(), e); setState(IDLE); } } break; case RECIVED_EVENT_RECORD: if (listener != null) { try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); } catch (Exception e) { logger.debug(e.getMessage(), e); } } break; } break; } case OPEN: { switch ((Event.Type) event.getType()) { case RECIVED_INTERIM_RECORD: try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); tsTask = runTsTimer(); if (context != null) context.sessionTimerStarted(this, tsTask); } catch (Exception e) { logger.debug(e.getMessage(), e); setState(IDLE); } break; case RECIVED_STOP_RECORD: try { listener.doAccRequestEvent(this, (AccountRequest) event.getData()); tsTask.cancel(true); if (context != null) context.srssionTimerCanceled(this, tsTask); setState(IDLE); } catch (Exception e) { logger.debug(e.getMessage(), e); setState(IDLE); } break; } break; } } } catch (Exception e) { logger.debug(e.getMessage(), e); return false; } return true; } private ScheduledFuture runTsTimer() { return scheduler.schedule(new Runnable() { public void run() { logger.debug("Ts timer expired"); if (context != null) try { context.sessionTimeoutElapses(ServerAccSessionImpl.this); } catch (InternalException e) { logger.debug(e.getMessage(), e); } setState(IDLE); } }, tsTimeout, TimeUnit.MILLISECONDS); } 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; } public <E> E getState(Class<E> eClass) { return eClass == ServerAccSessionState.class ? (E) state : null; } public Answer processRequest(Request request) { if (request.getCommandCode() == AccountRequestImpl.code) { try { sendAndStateLock.lock(); handleEvent(new Event(createAccountRequest(request))); } catch (Exception e) { logger.debug(e.getMessage(), e); } finally { sendAndStateLock.unlock(); } } else { try { listener.doOtherEvent(this, createAccountRequest(request), null); } catch (Exception e) { logger.debug(e.getMessage(), e); } } return null; } public void receivedSuccessMessage( Request request, Answer answer ) { if(request.getCommandCode() == AccountRequestImpl.code) { try { sendAndStateLock.lock(); handleEvent( new Event(createAccountRequest(request)) ); } catch (Exception e) { logger.debug(e.getMessage(), e); } finally { sendAndStateLock.unlock(); } try { listener.doAccRequestEvent(this, createAccountRequest(request)); } catch (Exception e) { logger.debug(e.getMessage(), e); } } else { try { listener.doOtherEvent(this, createAccountRequest(request), createAccountAnswer(answer)); } catch (Exception e) { logger.debug(e.getMessage(), e); } } } public void timeoutExpired(Request request) { // FIXME: alexandre: We don't do anything here... are we even getting this on server? } }