/servers/diameter/core/jdiameter/impl/src/main/java/org/jdiameter/client/impl/StackImpl.java
Java | 493 lines | 404 code | 48 blank | 41 comment | 78 complexity | 44d12897ec5e2305433e73411f8cea31 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
- /*
- * JBoss, Home of Professional Open Source
- * Copyright 2010, 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.client.impl;
-
- import static org.jdiameter.client.impl.helpers.ExtensionPoint.ControllerLayer;
- import static org.jdiameter.client.impl.helpers.ExtensionPoint.StackLayer;
- import static org.jdiameter.client.impl.helpers.ExtensionPoint.TransportLayer;
- import static org.jdiameter.client.impl.helpers.Parameters.Assembler;
- import static org.jdiameter.common.api.concurrent.IConcurrentFactory.ScheduledExecServices.ProcessingMessageTimer;
-
- import java.io.IOException;
- import java.util.List;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
-
- import org.jdiameter.api.AvpDataException;
- import org.jdiameter.api.BaseSession;
- import org.jdiameter.api.Configuration;
- import org.jdiameter.api.DisconnectCause;
- import org.jdiameter.api.IllegalDiameterStateException;
- import org.jdiameter.api.InternalException;
- import org.jdiameter.api.MetaData;
- import org.jdiameter.api.Mode;
- import org.jdiameter.api.NetworkReqListener;
- import org.jdiameter.api.Peer;
- import org.jdiameter.api.PeerState;
- import org.jdiameter.api.PeerTable;
- import org.jdiameter.api.RouteException;
- import org.jdiameter.api.SessionFactory;
- import org.jdiameter.api.app.StateChangeListener;
- import org.jdiameter.api.validation.Dictionary;
- import org.jdiameter.api.validation.ValidatorLevel;
- import org.jdiameter.client.api.IAssembler;
- import org.jdiameter.client.api.IContainer;
- import org.jdiameter.client.api.IMessage;
- import org.jdiameter.client.api.IMetaData;
- import org.jdiameter.client.api.StackState;
- import org.jdiameter.client.api.controller.IPeer;
- import org.jdiameter.client.api.controller.IPeerTable;
- import org.jdiameter.client.impl.helpers.Parameters;
- import org.jdiameter.common.api.concurrent.IConcurrentFactory;
- import org.jdiameter.common.api.data.ISessionDatasource;
- import org.jdiameter.common.api.statistic.IStatisticProcessor;
- import org.jdiameter.common.api.timer.ITimerFacility;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
-
- /**
- * Use stack extension point
- *
- * @author erick.svenson@yahoo.com
- * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
- * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
- */
- public class StackImpl implements IContainer, StackImplMBean {
-
- private static final Logger log = LoggerFactory.getLogger(StackImpl.class);
-
- protected IAssembler assembler;
- protected IConcurrentFactory concurrentFactory;
- protected Configuration config;
- protected IPeerTable peerManager;
- protected StackState state = StackState.IDLE;
- protected Lock lock = new ReentrantLock();
-
- /**
- * Use for processing request time-out tasks (for all active peers)
- */
- protected ScheduledExecutorService scheduledFacility;
-
- @SuppressWarnings("unchecked")
- public SessionFactory init(Configuration config) throws IllegalDiameterStateException, InternalException {
- lock.lock();
- if (log.isInfoEnabled()) {
- log.info("(-)(-)(-)(-)(-) Starting " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
- }
- try {
- if (state != StackState.IDLE) {
- throw new IllegalDiameterStateException();
- }
-
- try {
- Class assemblerClass = Class.forName(config.getStringValue(Assembler.ordinal(), (String) Assembler.defValue()));
- assembler = (IAssembler) assemblerClass.getConstructor(Configuration.class).newInstance(config);
- // register common instances
- assembler.registerComponentInstance(this);
- assembler.registerComponentInstance(config);
- }
- catch (Exception e) {
- throw new InternalException(e);
- }
- this.config = config;
- this.concurrentFactory = (IConcurrentFactory) assembler.getComponentInstance(IConcurrentFactory.class);
-
- try {
- Configuration[] dictionaryConfigs = config.getChildren(Parameters.Dictionary.ordinal());
-
- // Initialize with default values
- String dictionaryClassName = (String) Parameters.DictionaryClass.defValue();
- Boolean validatorEnabled = (Boolean) Parameters.DictionaryEnabled.defValue();
- ValidatorLevel validatorSendLevel = ValidatorLevel.fromString((String) Parameters.DictionarySendLevel.defValue());
- ValidatorLevel validatorReceiveLevel = ValidatorLevel.fromString((String) Parameters.DictionaryReceiveLevel.defValue());
-
- if (dictionaryConfigs != null && dictionaryConfigs.length > 0) {
- Configuration dictionaryConfiguration = dictionaryConfigs[0];
- dictionaryClassName = dictionaryConfiguration.getStringValue(Parameters.DictionaryClass.ordinal(), (String) Parameters.DictionaryClass.defValue());
- validatorEnabled = dictionaryConfiguration.getBooleanValue(Parameters.DictionaryEnabled.ordinal(), (Boolean) Parameters.DictionaryEnabled.defValue());
- validatorSendLevel = ValidatorLevel.fromString(dictionaryConfiguration.getStringValue(Parameters.DictionarySendLevel.ordinal(),
- (String) Parameters.DictionarySendLevel.defValue()));
- validatorReceiveLevel = ValidatorLevel.fromString(dictionaryConfiguration.getStringValue(Parameters.DictionaryReceiveLevel.ordinal(),
- (String) Parameters.DictionaryReceiveLevel.defValue()));
- }
-
- createDictionary(dictionaryClassName, validatorEnabled, validatorSendLevel, validatorReceiveLevel);
- }
- catch (Exception e) {
- throw new InternalException(e);
- }
-
- // create manager
- this.peerManager = (IPeerTable) assembler.getComponentInstance(IPeerTable.class);
- this.peerManager.setAssembler(assembler);
-
- this.state = StackState.CONFIGURED;
- }
- finally {
- lock.unlock();
- }
- if (log.isInfoEnabled()) {
- log.info("(-)(-)(-)(-)(-) Started " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
- }
- return (SessionFactory) assembler.getComponentInstance(SessionFactory.class);
- }
-
- private void createDictionary(String clazz, boolean validatorEnabled, ValidatorLevel validatorSendLevel, ValidatorLevel validatorReceiveLevel)
- throws InternalException {
- // Defer call to singleton
- DictionarySingleton.init(clazz, validatorEnabled, validatorSendLevel, validatorReceiveLevel);
- }
-
- public SessionFactory getSessionFactory() throws IllegalDiameterStateException {
- if (state == StackState.CONFIGURED || state == StackState.STARTED) {
- // FIXME: When possible, get rid of IoC here.
- return (SessionFactory) assembler.getComponentInstance(SessionFactory.class);
- }
- else {
- throw new IllegalDiameterStateException();
- }
- }
-
- public Dictionary getDictionary() throws IllegalDiameterStateException {
- return DictionarySingleton.getDictionary();
- }
-
- public void start() throws IllegalDiameterStateException, InternalException {
- lock.lock();
- try {
- if (state != StackState.STOPPED && state != StackState.CONFIGURED) {
- throw new IllegalDiameterStateException();
- }
-
- scheduledFacility = concurrentFactory.getScheduledExecutorService(ProcessingMessageTimer.name());
- assembler.getComponentInstance(ISessionDatasource.class).start();
- assembler.getComponentInstance(IStatisticProcessor.class).start();
- assembler.getComponentInstance(ITimerFacility.class);
- startPeerManager();
- state = StackState.STARTED;
- }
- finally {
- lock.unlock();
- }
- }
-
- @SuppressWarnings("unchecked")
- public void start(final Mode mode, long timeOut, TimeUnit timeUnit) throws IllegalDiameterStateException, InternalException {
- lock.lock();
- try {
- if (state != StackState.STOPPED && state != StackState.CONFIGURED) {
- throw new IllegalDiameterStateException();
- }
- scheduledFacility = concurrentFactory.getScheduledExecutorService(ProcessingMessageTimer.name());
- assembler.getComponentInstance(IStatisticProcessor.class).start();
- assembler.getComponentInstance(ISessionDatasource.class).start();
- assembler.getComponentInstance(ITimerFacility.class);
- List<Peer> peerTable = peerManager.getPeerTable();
- // considering only "to connect" peers are on the table at this time...
- final CountDownLatch barrier = new CountDownLatch(Mode.ANY_PEER.equals(mode) ? Math.min(peerTable.size(), 1) : peerTable.size());
- StateChangeListener listener = new AbstractStateChangeListener() {
- public void stateChanged(Enum oldState, Enum newState) {
- if (PeerState.OKAY.equals(newState)) {
- barrier.countDown();
- }
- }
- };
- for (Peer p : peerTable) {
- ((IPeer) p).addStateChangeListener(listener);
- }
- startPeerManager();
- try {
- barrier.await(timeOut, timeUnit);
- if (barrier.getCount() != 0) {
- throw new InternalException("TimeOut");
- }
- state = StackState.STARTED;
- }
- catch (InterruptedException e) {
- throw new InternalException("TimeOut");
- }
- finally {
- for (Peer p : peerTable) {
- ((IPeer) p).remStateChangeListener(listener);
- }
- }
- }
- finally {
- lock.unlock();
- }
- }
-
- private void startPeerManager() throws InternalException {
- try {
- if (peerManager != null) {
- peerManager.start();
- }
- getMetaData().unwrap(IMetaData.class).updateLocalHostStateId();
- }
- catch (Exception e) {
- throw new InternalException(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- public void stop(long timeOut, TimeUnit timeUnit, int disconnectCause) throws IllegalDiameterStateException, InternalException {
- lock.lock();
- try {
- if (state == StackState.STARTED || state == StackState.CONFIGURED) {
- if (log.isInfoEnabled()) {
- log.info("(-)(-)(-)(-)(-) Stopping " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
- }
- List<Peer> peerTable = peerManager.getPeerTable();
- final CountDownLatch barrier = new CountDownLatch(peerTable.size());
- StateChangeListener listener = new AbstractStateChangeListener() {
- public void stateChanged(Enum oldState, Enum newState) {
- if (PeerState.DOWN.equals(newState)) {
- barrier.countDown();
- }
- }
- };
- for (Peer p : peerTable) {
- if (p.getState(PeerState.class).equals(PeerState.DOWN)) {
- barrier.countDown();
- }
- else {
- ((IPeer) p).addStateChangeListener(listener);
- }
- }
- if (peerManager != null) {
- try {
- peerManager.stopping(disconnectCause);
- }
- catch (Exception e) {
- log.warn("Stopping error", e);
- }
- }
- try {
- barrier.await(timeOut, timeUnit);
- if (barrier.getCount() != 0) {
- throw new InternalException("TimeOut");
- }
- }
- catch (InterruptedException e) {
- throw new InternalException("TimeOut");
- }
- finally {
- state = StackState.STOPPED;
- for (Peer p : peerTable) {
- ((IPeer) p).remStateChangeListener(listener);
- }
- }
- assembler.getComponentInstance(ISessionDatasource.class).stop();
- assembler.getComponentInstance(IStatisticProcessor.class).stop();
- try {
- if (peerManager != null) {
- peerManager.stopped();
- }
- // Clear all timeout tasks
- if (scheduledFacility != null) {
- concurrentFactory.shutdownNow(scheduledFacility);
- }
- }
- catch (Exception e) {
- log.warn("Stopped error", e);
- }
- state = StackState.STOPPED;
- if (log.isInfoEnabled()) {
- log.info("(-)(-)(-)(-)(-) Stopped " + VersionProperties.instance.getProperty("vendor") + " DIAMETER Stack v" + VersionProperties.instance.getProperty("version") + " (-)(-)(-)(-)(-)");
- }
- }
- }
- finally {
- lock.unlock();
- }
- }
-
- public void destroy() {
- // Be friendly
- if (state == StackState.STARTED) {
- log.warn("Calling destroy() with Stack in STARTED state. Calling stop(REBOOTING) before, please do it yourself with the proper cause.");
- stop(DisconnectCause.REBOOTING);
- }
-
- lock.lock();
- try {
- if (peerManager != null) {
- peerManager.destroy();
- }
- if (assembler != null) {
- assembler.destroy();
- }
- if (scheduledFacility != null) {
- concurrentFactory.shutdownNow(scheduledFacility);
- }
- }
- catch (Exception e) {
- log.warn("Destroy error", e);
- }
- finally {
- state = StackState.IDLE;
- lock.unlock();
- }
- }
-
- public boolean isActive() {
- return state == StackState.STARTED;
- }
-
- public java.util.logging.Logger getLogger() {
- return java.util.logging.Logger.getAnonymousLogger();
- }
-
- public MetaData getMetaData() {
- if (state == StackState.IDLE) {
- throw new IllegalStateException("Meta data not defined");
- }
- return (MetaData) assembler.getComponentInstance(IMetaData.class);
- }
-
- @SuppressWarnings("unchecked")
- public <T extends BaseSession> T getSession(String sessionId, Class<T> clazz) throws InternalException {
- if (getState() == StackState.IDLE) {
- throw new InternalException("Illegal state of stack");
- }
- BaseSession bs = assembler.getComponentInstance(ISessionDatasource.class).getSession(sessionId);
- return bs != null ? (T) bs : null;
- }
-
- public boolean isWrapperFor(Class<?> aClass) throws InternalException {
- boolean isWrap = aClass == PeerTable.class;
- if (!isWrap) {
- isWrap = assembler.getChilds()[StackLayer.id()].getComponentInstance(aClass) != null;
- }
- if (!isWrap) {
- isWrap = assembler.getChilds()[ControllerLayer.id()].getComponentInstance(aClass) != null;
- }
- if (!isWrap) {
- isWrap = assembler.getChilds()[TransportLayer.id()].getComponentInstance(aClass) != null;
- }
- return isWrap;
- }
-
- @SuppressWarnings("unchecked")
- public <T> T unwrap(Class<T> aClass) throws InternalException {
- Object unwrapObject = null;
- if (aClass == PeerTable.class) {
- unwrapObject = assembler.getComponentInstance(aClass);
- }
- // TODO: "layers" should be removed....
- if (unwrapObject == null) {
- unwrapObject = assembler.getChilds()[StackLayer.id()].getComponentInstance(aClass);
- }
- if (unwrapObject == null) {
- unwrapObject = assembler.getChilds()[ControllerLayer.id()].getComponentInstance(aClass);
- }
- if (unwrapObject == null) {
- unwrapObject = assembler.getChilds()[TransportLayer.id()].getComponentInstance(aClass);
- }
- return (T) unwrapObject;
- }
-
- // Extended methods
-
- public StackState getState() {
- return state;
- }
-
- public Configuration getConfiguration() {
- return config;
- }
-
- public IAssembler getAssemblerFacility() {
- return assembler;
- }
-
- public void sendMessage(IMessage message) throws RouteException, AvpDataException, IllegalDiameterStateException, IOException {
- peerManager.sendMessage(message);
- }
-
- public void addSessionListener(String sessionId, NetworkReqListener listener) {
- peerManager.addSessionReqListener(sessionId, listener);
- }
-
- public void removeSessionListener(String sessionId) {
- peerManager.removeSessionListener(sessionId);
- }
-
- public ScheduledExecutorService getScheduledFacility() {
- return scheduledFacility;
- }
-
- public IConcurrentFactory getConcurrentFactory() {
- return this.concurrentFactory;
- }
-
- public String configuration() {
- return config != null ? config.toString() : "not set";
- }
-
- public String metaData() {
- try {
- return getMetaData().toString();
- }
- catch (Exception exc) {
- return "not set";
- }
- }
-
- public String peerDescription(String name) {
- try {
- for (Peer p : unwrap(PeerTable.class).getPeerTable()) {
- if (p.getUri().getFQDN().equals(name)) {
- return p.toString();
- }
- }
- }
- catch (InternalException e) {
- log.debug("InternalException", e);
- }
-
- return "not set";
- }
-
- public String peerList() {
- try {
- return unwrap(PeerTable.class).getPeerTable().toString();
- }
- catch (InternalException e) {
- return "not set";
- }
- }
-
- public void stop(int disconnectCause) {
- try {
- stop(10, TimeUnit.SECONDS, disconnectCause);
- }
- catch (Exception e) {
- log.debug("Exception", e);
- }
- }
-
- }