package org.jdiameter.client.impl.controller; /* * Copyright (c) 2006 jDiameter. * https://jdiameter.dev.java.net/ * * License: GPL v3 * * e-mail: erick.svenson@yahoo.com * */ import static org.jdiameter.client.impl.helpers.Parameters.PeerIp; import static org.jdiameter.client.impl.helpers.Parameters.PeerLocalPortRange; import static org.jdiameter.client.impl.helpers.Parameters.PeerName; import static org.jdiameter.client.impl.helpers.Parameters.PeerRating; import static org.jdiameter.client.impl.helpers.Parameters.StopTimeOut; import java.io.IOException; import java.net.URISyntaxException; import java.net.UnknownServiceException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.jdiameter.api.Avp; import org.jdiameter.api.AvpDataException; import org.jdiameter.api.Configuration; import org.jdiameter.api.IllegalDiameterStateException; import org.jdiameter.api.InternalException; import org.jdiameter.api.MetaData; import org.jdiameter.api.NetworkReqListener; import org.jdiameter.api.Peer; import org.jdiameter.api.RouteException; import org.jdiameter.api.URI; import org.jdiameter.client.api.IAssembler; import org.jdiameter.client.api.IMessage; import org.jdiameter.client.api.IMetaData; import org.jdiameter.client.api.controller.IPeer; import org.jdiameter.client.api.controller.IPeerTable; import org.jdiameter.client.api.fsm.IFsmFactory; import org.jdiameter.client.api.io.ITransportLayerFactory; import org.jdiameter.client.api.io.TransportException; import org.jdiameter.client.api.parser.IMessageParser; import org.jdiameter.client.api.router.IRouter; import org.jdiameter.client.impl.helpers.Parameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PeerTableImpl implements IPeerTable { protected Logger logger = LoggerFactory.getLogger(PeerTableImpl.class); // Peer table protected ConcurrentHashMap<URI,Peer> peerTable = new ConcurrentHashMap<URI,Peer>(); protected boolean isStarted; protected long stopTimeOut; protected IAssembler assembler; protected IRouter router; protected MetaData metaData; protected ExecutorService peerTaskExecutor; protected ConcurrentHashMap<String, NetworkReqListener> sessionReqListeners = new ConcurrentHashMap<String, NetworkReqListener>(); public PeerTableImpl(Configuration globalConfig, MetaData metaData, IRouter router, IFsmFactory fsmFactory, ITransportLayerFactory transportFactory, IMessageParser parser) { init(router, globalConfig, metaData, fsmFactory, transportFactory, parser); } protected PeerTableImpl() { } protected void init(IRouter router, Configuration globalConfig, MetaData metaData, IFsmFactory fsmFactory, ITransportLayerFactory transportFactory, IMessageParser parser) { this.router = router; this.metaData = metaData; this.stopTimeOut = globalConfig.getLongValue(StopTimeOut.ordinal(), (Long) StopTimeOut.defValue()); this.peerTaskExecutor = Executors.newCachedThreadPool(); Configuration[] peers = globalConfig.getChildren( Parameters.PeerTable.ordinal() ); if (peers != null && peers.length > 0) { for (Configuration peerConfig : peers) { if (peerConfig.isAttributeExist(PeerName.ordinal())) { String uri = peerConfig.getStringValue(PeerName.ordinal(), null); int rating = peerConfig.getIntValue(PeerRating.ordinal(), 0); String ip = peerConfig.getStringValue(PeerIp.ordinal(), null); String portRange = peerConfig.getStringValue(PeerLocalPortRange.ordinal(), null); try { // create predefined peer IPeer peer = (IPeer) createPeer(rating, uri, ip, portRange, metaData, globalConfig, peerConfig, fsmFactory, transportFactory, parser); if (peer != null) { peer.setRealm(router.getRealmForPeer(peer.getUri().getFQDN())); peerTable.put(peer.getUri(), peer); logger.debug("Append peer {} to peer table", peer); } } catch (Exception e) { logger.warn("Can not create peer {}", uri, e); } } } } } protected Peer createPeer(int rating, String uri, String ip, String portRange, MetaData metaData, Configuration config, Configuration peerConfig, IFsmFactory fsmFactory, ITransportLayerFactory transportFactory, IMessageParser parser) throws InternalException, TransportException, URISyntaxException, UnknownServiceException { return new PeerImpl( this, rating, new URI(uri), ip, portRange, metaData.unwrap(IMetaData.class), config, peerConfig, fsmFactory, transportFactory, parser ); } public List<Peer> getPeerTable() { List<Peer> p = new ArrayList<Peer>(); p.addAll(peerTable.values()); return p; } public Peer getPeer(String name) { return getPeerByName(name); } public void sendMessage(IMessage message) throws IllegalDiameterStateException, RouteException, AvpDataException, IOException { if ( !isStarted) throw new IllegalDiameterStateException( "Stack is down" ); // Get context IPeer peer; if (message.isRequest()) { logger.debug("Send request {} [destHost={}; destRealm={}]", new Object[] {message, message.getAvps().getAvp(Avp.DESTINATION_HOST) != null ? message.getAvps().getAvp(Avp.DESTINATION_HOST).getOctetString() : "", message.getAvps().getAvp(Avp.DESTINATION_REALM) != null ? message.getAvps().getAvp(Avp.DESTINATION_REALM).getOctetString() : ""} ); // Check local request peer = router.getPeer(message, this); logger.debug( "Selected peer {} for sending message {}", new Object[] {peer, message}); if (peer == metaData.getLocalPeer()) { logger.debug("Request {} will be processed by local service",message); } else { message.setHopByHopIdentifier( peer.getHopByHopIdentifier() ); peer.addMessage(message); message.setPeer(peer); } } else { peer = message.getPeer(); if (peer == null) { peer = router.getPeer(message, this); if (peer == null) { throw new RouteException( "Cannot found remote context for sending message" ); } message.setPeer(peer); } } try { if ( !peer.sendMessage(message) ) { throw new IOException( "Can not send message" ); } } catch(Exception e) { throw new IOException(e.getMessage()); } } public void addSessionReqListener(String sessionId, NetworkReqListener listener) { sessionReqListeners.put(sessionId, listener); } public Map<String, NetworkReqListener> getSessionReqListeners() { return sessionReqListeners; } public IPeer getPeerByName(String peerName) { for (Peer p: peerTable.values()) { if (p.getUri().getFQDN().equals(peerName)) { return (IPeer) p; } } return null; } public IPeer getPeerByUri(String peerUri) { URI otherUri; try { otherUri = new URI(peerUri); } catch (Exception e) { return null; } for (Peer p: peerTable.values()) { if (p.getUri().getFQDN().equals(otherUri.getFQDN())) { return (IPeer) p; } } return null; } public void removeSessionListener(String sessionId) { sessionReqListeners.remove(sessionId); } public void setAssempler(IAssembler assembler) { this.assembler = assembler; } // Life cycle public void start() throws IllegalDiameterStateException, IOException { if (peerTaskExecutor.isShutdown()) { peerTaskExecutor = Executors.newCachedThreadPool(); } for(Peer peer: peerTable.values()) { try { peer.connect(); } catch (Exception e) { logger.debug("Can not start connect procedure to peer {}", peer, e); } } router.start(); isStarted = true; } public ExecutorService getPeerTaskExecutor() { return peerTaskExecutor; } public void stopped() { if (sessionReqListeners != null) { sessionReqListeners.clear(); } for (Peer p : peerTable.values()) { for (IMessage m : ((IPeer)p).remAllMessage()) { try { m.runTimer(); } catch(Exception e) {} } } if (peerTaskExecutor != null) { try { peerTaskExecutor.shutdownNow(); } catch (Exception e) { logger.warn("Can not stop executor"); } } router.stop(); } public void stopping() { isStarted = false; for(Peer peer : peerTable.values()) { try { peer.disconnect(); } catch (Exception e) { logger.warn("Can not stopping peer table", e); } } } public void destroy() { Executors.unconfigurableExecutorService(peerTaskExecutor); if (router != null) { router.destroy(); } router = null; peerTable = null; assembler = null; } // Extension interface public boolean isWrapperFor(Class<?> aClass) throws InternalException { return false; } public <T> T unwrap(Class<T> aClass) throws InternalException { return null; } }