/protocols/ss7/m3ua/impl/src/main/java/org/mobicents/protocols/ss7/m3ua/impl/M3UAManagement.java
Java | 659 lines | 430 code | 126 blank | 103 comment | 94 complexity | 42ebf0f39ab4ee71257acdca8dad0ef1 MD5 | raw file
1/* 2 * JBoss, Home of Professional Open Source 3 * Copyright 2011, Red Hat, Inc. and individual contributors 4 * by the @authors tag. See the copyright.txt in the distribution for a 5 * full listing of individual contributors. 6 * 7 * This is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU Lesser General Public License as 9 * published by the Free Software Foundation; either version 2.1 of 10 * the License, or (at your option) any later version. 11 * 12 * This software is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this software; if not, write to the Free 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 21 */ 22 23package org.mobicents.protocols.ss7.m3ua.impl; 24 25import java.io.File; 26import java.io.FileInputStream; 27import java.io.FileNotFoundException; 28import java.io.FileOutputStream; 29import java.io.IOException; 30import java.util.concurrent.Executors; 31import java.util.concurrent.ScheduledExecutorService; 32import java.util.concurrent.TimeUnit; 33 34import javolution.text.TextBuilder; 35import javolution.util.FastList; 36import javolution.util.FastMap; 37import javolution.xml.XMLObjectReader; 38import javolution.xml.XMLObjectWriter; 39import javolution.xml.stream.XMLStreamException; 40 41import org.apache.log4j.Logger; 42import org.mobicents.protocols.api.Association; 43import org.mobicents.protocols.api.Management; 44import org.mobicents.protocols.ss7.m3ua.ExchangeType; 45import org.mobicents.protocols.ss7.m3ua.Functionality; 46import org.mobicents.protocols.ss7.m3ua.IPSPType; 47import org.mobicents.protocols.ss7.m3ua.impl.fsm.FSM; 48import org.mobicents.protocols.ss7.m3ua.impl.message.MessageFactoryImpl; 49import org.mobicents.protocols.ss7.m3ua.impl.oam.M3UAOAMMessages; 50import org.mobicents.protocols.ss7.m3ua.impl.parameter.ParameterFactoryImpl; 51import org.mobicents.protocols.ss7.m3ua.impl.scheduler.M3UAScheduler; 52import org.mobicents.protocols.ss7.m3ua.message.MessageClass; 53import org.mobicents.protocols.ss7.m3ua.message.MessageFactory; 54import org.mobicents.protocols.ss7.m3ua.message.MessageType; 55import org.mobicents.protocols.ss7.m3ua.message.transfer.PayloadData; 56import org.mobicents.protocols.ss7.m3ua.parameter.NetworkAppearance; 57import org.mobicents.protocols.ss7.m3ua.parameter.ParameterFactory; 58import org.mobicents.protocols.ss7.m3ua.parameter.ProtocolData; 59import org.mobicents.protocols.ss7.m3ua.parameter.RoutingContext; 60import org.mobicents.protocols.ss7.m3ua.parameter.TrafficModeType; 61import org.mobicents.protocols.ss7.mtp.Mtp3PausePrimitive; 62import org.mobicents.protocols.ss7.mtp.Mtp3ResumePrimitive; 63import org.mobicents.protocols.ss7.mtp.Mtp3StatusPrimitive; 64import org.mobicents.protocols.ss7.mtp.Mtp3TransferPrimitive; 65import org.mobicents.protocols.ss7.mtp.Mtp3UserPartBaseImpl; 66 67/** 68 * @author amit bhayani 69 * 70 */ 71public class M3UAManagement extends Mtp3UserPartBaseImpl { 72 private static final Logger logger = Logger.getLogger(M3UAManagement.class); 73 private static final String AS_LIST = "asList"; 74 private static final String ASP_FACTORY_LIST = "aspFactoryList"; 75 private static final String DPC_VS_AS_LIST = "route"; 76 77 private static final String M3UA_PERSIST_DIR_KEY = "m3ua.persist.dir"; 78 private static final String USER_DIR_KEY = "user.dir"; 79 private static final String PERSIST_FILE_NAME = "m3ua.xml"; 80 81 private static final M3UAXMLBinding binding = new M3UAXMLBinding(); 82 private static final String TAB_INDENT = "\t"; 83 private static final String CLASS_ATTRIBUTE = "type"; 84 85 protected FastList<As> appServers = new FastList<As>(); 86 protected FastList<AspFactory> aspfactories = new FastList<AspFactory>(); 87 88 protected M3UAScheduler m3uaScheduler = new M3UAScheduler(); 89 90 private final TextBuilder persistFile = TextBuilder.newInstance(); 91 92 private final String name; 93 94 private String persistDir = null; 95 96 protected ParameterFactory parameterFactory = new ParameterFactoryImpl(); 97 protected MessageFactory messageFactory = new MessageFactoryImpl(); 98 99 protected Management transportManagement = null; 100 101 private ScheduledExecutorService fsmTicker; 102 103 protected int maxAsForRoute = 4; 104 105 private M3UARouteManagement routeManagement = null; 106 107 public M3UAManagement(String name) { 108 this.name = name; 109 binding.setClassAttribute(CLASS_ATTRIBUTE); 110 binding.setAlias(AspFactory.class, "aspFactory"); 111 binding.setAlias(As.class, "as"); 112 binding.setAlias(Asp.class, "asp"); 113 114 this.routeManagement = new M3UARouteManagement(this); 115 116 } 117 118 public String getName() { 119 return name; 120 } 121 122 public String getPersistDir() { 123 return persistDir; 124 } 125 126 public void setPersistDir(String persistDir) { 127 this.persistDir = persistDir; 128 } 129 130 public int getMaxAsForRoute() { 131 return maxAsForRoute; 132 } 133 134 public void setMaxAsForRoute(int maxAsForRoute) { 135 this.maxAsForRoute = maxAsForRoute; 136 } 137 138 public Management getTransportManagement() { 139 return transportManagement; 140 } 141 142 public void setTransportManagement(Management transportManagement) { 143 this.transportManagement = transportManagement; 144 } 145 146 public void start() throws Exception { 147 148 if (this.transportManagement == null) { 149 throw new NullPointerException("TransportManagement is null"); 150 } 151 152 if (maxAsForRoute < 1 || maxAsForRoute > 4) { 153 throw new Exception("Max AS for a route can be minimum 1 or maximum 4"); 154 } 155 156 super.start(); 157 158 this.persistFile.clear(); 159 160 if (persistDir != null) { 161 this.persistFile.append(persistDir).append(File.separator).append(this.name).append("_") 162 .append(PERSIST_FILE_NAME); 163 } else { 164 persistFile.append(System.getProperty(M3UA_PERSIST_DIR_KEY, System.getProperty(USER_DIR_KEY))) 165 .append(File.separator).append(this.name).append("_").append(PERSIST_FILE_NAME); 166 } 167 168 logger.info(String.format("M3UA configuration file path %s", persistFile.toString())); 169 170 binding.setM3uaManagement(this); 171 172 try { 173 this.load(); 174 } catch (FileNotFoundException e) { 175 logger.warn(String.format("Failed to load the SS7 configuration file. \n%s", e.getMessage())); 176 } 177 178 this.routeManagement.reset(); 179 180 fsmTicker = Executors.newSingleThreadScheduledExecutor(); 181 fsmTicker.scheduleAtFixedRate(m3uaScheduler, 500, 500, TimeUnit.MILLISECONDS); 182 183 logger.info("Started M3UAManagement"); 184 } 185 186 public void stop() throws Exception { 187 super.stop(); 188 189 this.store(); 190 fsmTicker.shutdown(); 191 } 192 193 public FastList<As> getAppServers() { 194 return appServers; 195 } 196 197 public FastList<AspFactory> getAspfactories() { 198 return aspfactories; 199 } 200 201 public FastMap<String, As[]> getRoute() { 202 return this.routeManagement.route; 203 } 204 205 protected As getAs(String asName) { 206 for (FastList.Node<As> n = appServers.head(), end = appServers.tail(); (n = n.getNext()) != end;) { 207 As as = n.getValue(); 208 if (as.getName().equals(asName)) { 209 return as; 210 } 211 } 212 return null; 213 } 214 215 /** 216 * <p> 217 * Create new {@link As} 218 * </p> 219 * <p> 220 * Command is m3ua as create <as-name> <AS | SGW | IPSP> mode <SE | DE> 221 * ipspType < client | server > rc <routing-context> traffic-mode <traffic 222 * mode> 223 * </p> 224 * <p> 225 * where mode is optional, by default SE. ipspType should be specified if 226 * type is IPSP. rc is optional and traffi-mode is also optional, default is 227 * Loadshare 228 * </p> 229 * 230 * @param args 231 * @return 232 * @throws Exception 233 */ 234 public As createAs(String asName, Functionality functionality, ExchangeType exchangeType, IPSPType ipspType, 235 RoutingContext rc, TrafficModeType trafficMode, NetworkAppearance na) throws Exception { 236 237 As as = this.getAs(asName); 238 if (as != null) { 239 throw new Exception(String.format(M3UAOAMMessages.CREATE_AS_FAIL_NAME_EXIST, asName)); 240 } 241 242 // TODO check if RC is already taken? 243 244 if (exchangeType == null) { 245 exchangeType = ExchangeType.SE; 246 } 247 248 if (functionality == Functionality.IPSP && ipspType == null) { 249 ipspType = IPSPType.CLIENT; 250 } 251 252 as = new As(asName, rc, trafficMode, functionality, exchangeType, ipspType, na); 253 as.setM3UAManagement(this); 254 FSM localFSM = as.getLocalFSM(); 255 this.m3uaScheduler.execute(localFSM); 256 257 FSM peerFSM = as.getPeerFSM(); 258 this.m3uaScheduler.execute(peerFSM); 259 260 appServers.add(as); 261 262 this.store(); 263 264 return as; 265 } 266 267 public As destroyAs(String asName) throws Exception { 268 As as = this.getAs(asName); 269 if (as == null) { 270 throw new Exception(String.format(M3UAOAMMessages.ADD_ASP_TO_AS_FAIL_NO_AS, asName)); 271 } 272 273 if (as.getAspList().size() != 0) { 274 throw new Exception(String.format( 275 "As=%s still has ASP's assigned. Unassign Asp's before destroying this As", asName)); 276 } 277 278 for (FastMap.Entry<String, As[]> e = this.routeManagement.route.head(), end = this.routeManagement.route.tail(); (e = e 279 .getNext()) != end;) { 280 As[] asList = e.getValue(); 281 for (int count = 0; count < asList.length; count++) { 282 As asTemp = asList[count]; 283 if (asTemp != null && asTemp.equals(as)) { 284 throw new Exception(String.format("As=%s used in route=%s. Remove from route", asName, e.getKey())); 285 } 286 } 287 } 288 289 FSM asLocalFSM = as.getLocalFSM(); 290 if (asLocalFSM != null) { 291 asLocalFSM.cancel(); 292 } 293 294 FSM asPeerFSM = as.getPeerFSM(); 295 if (asPeerFSM != null) { 296 asPeerFSM.cancel(); 297 } 298 299 appServers.remove(as); 300 301 this.store(); 302 303 return as; 304 } 305 306 /** 307 * Create new {@link AspFactory} 308 * 309 * @param args 310 * @return 311 * @throws Exception 312 */ 313 public AspFactory createAspFactory(String aspName, String associationName) throws Exception { 314 AspFactory factory = this.getAspFactory(aspName); 315 316 if (factory != null) { 317 throw new Exception(String.format(M3UAOAMMessages.CREATE_ASP_FAIL_NAME_EXIST, aspName)); 318 } 319 320 Association association = this.transportManagement.getAssociation(associationName); 321 if (association == null) { 322 throw new Exception(String.format("No Association found for name=%s", associationName)); 323 } 324 325 if (association.isStarted()) { 326 throw new Exception(String.format("Association=%s is started", associationName)); 327 } 328 329 if (association.getAssociationListener() != null) { 330 throw new Exception(String.format("Association=%s is already associated", associationName)); 331 } 332 333 factory = new AspFactory(aspName); 334 factory.setAssociation(association); 335 factory.setTransportManagement(this.transportManagement); 336 337 aspfactories.add(factory); 338 339 this.store(); 340 341 return factory; 342 } 343 344 public AspFactory destroyAspFactory(String aspName) throws Exception { 345 AspFactory aspFactroy = this.getAspFactory(aspName); 346 if (aspFactroy == null) { 347 throw new Exception(String.format(M3UAOAMMessages.ADD_ASP_TO_AS_FAIL_NO_ASP, aspName)); 348 } 349 350 if (aspFactroy.getAspList().size() != 0) { 351 throw new Exception("Asp are still assigned to As. Unassign all"); 352 } 353 aspFactroy.unsetAssociation(); 354 this.aspfactories.remove(aspFactroy); 355 this.store(); 356 357 return aspFactroy; 358 } 359 360 /** 361 * Associate {@link Asp} to {@link As} 362 * 363 * @param asName 364 * @param aspName 365 * @return 366 * @throws Exception 367 */ 368 public Asp assignAspToAs(String asName, String aspName) throws Exception { 369 // check ASP and AS exist with given name 370 As as = this.getAs(asName); 371 372 if (as == null) { 373 throw new Exception(String.format(M3UAOAMMessages.ADD_ASP_TO_AS_FAIL_NO_AS, asName)); 374 } 375 376 AspFactory aspFactroy = this.getAspFactory(aspName); 377 378 if (aspFactroy == null) { 379 throw new Exception(String.format(M3UAOAMMessages.ADD_ASP_TO_AS_FAIL_NO_ASP, aspName)); 380 } 381 382 // If ASP already assigned to AS we don't want to re-assign 383 for (FastList.Node<Asp> n = as.getAspList().head(), end = as.getAspList().tail(); (n = n.getNext()) != end;) { 384 Asp asp = n.getValue(); 385 if (asp.getName().equals(aspName)) { 386 throw new Exception(String.format( 387 "Cannot assign ASP=%s to AS=%s. This ASP is already assigned to this AS", aspName, asName)); 388 } 389 } 390 391 FastList<Asp> asps = aspFactroy.getAspList(); 392 393 // Checks for RoutingContext. We know that for null RC there will always 394 // be a single ASP assigned to AS and ASP cannot be shared 395 if (as.getRoutingContext() == null) { 396 // If AS has Null RC, this should be the first assignment of ASP to 397 // AS 398 if (asps.size() != 0) { 399 throw new Exception(String.format( 400 "Cannot assign ASP=% to AS=%. This ASP is already assigned to other AS.", aspName, asName)); 401 } 402 } else if (asps.size() > 0) { 403 // RoutingContext is not null, make sure there is no ASP that is 404 // assigned to AS with null RC 405 Asp asp = asps.get(0); 406 if (asp != null && asp.getAs().getRoutingContext() == null) { 407 throw new Exception( 408 String.format( 409 "Cannot assign ASP=% to AS=%. This ASP is already assigned to other AS which has null RoutingContext.", 410 aspName, asName)); 411 } 412 } 413 414 if (aspFactroy.getFunctionality() != null && aspFactroy.getFunctionality() != as.getFunctionality()) { 415 throw new Exception(String.format( 416 "Cannot assign ASP=% to AS=%. This ASP is already assigned to other AS of type=%s", aspName, 417 asName, aspFactroy.getFunctionality())); 418 } 419 420 if (aspFactroy.getExchangeType() != null && aspFactroy.getExchangeType() != as.getExchangeType()) { 421 throw new Exception(String.format( 422 "Cannot assign ASP=% to AS=%. This ASP is already assigned to other AS of ExchangeType=%s", 423 aspName, asName, aspFactroy.getExchangeType())); 424 } 425 426 if (aspFactroy.getIpspType() != null && aspFactroy.getIpspType() != as.getIpspType()) { 427 throw new Exception(String.format( 428 "Cannot assign ASP=% to AS=%. This ASP is already assigned to other AS of which has IPSP type=%s", 429 aspName, asName, aspFactroy.getIpspType())); 430 } 431 432 aspFactroy.setExchangeType(as.getExchangeType()); 433 aspFactroy.setFunctionality(as.getFunctionality()); 434 aspFactroy.setIpspType(as.getIpspType()); 435 436 Asp asp = aspFactroy.createAsp(); 437 FSM aspLocalFSM = asp.getLocalFSM(); 438 m3uaScheduler.execute(aspLocalFSM); 439 440 FSM aspPeerFSM = asp.getPeerFSM(); 441 m3uaScheduler.execute(aspPeerFSM); 442 as.addAppServerProcess(asp); 443 444 this.store(); 445 446 return asp; 447 } 448 449 public Asp unassignAspFromAs(String asName, String aspName) throws Exception { 450 // check ASP and AS exist with given name 451 As as = this.getAs(asName); 452 453 if (as == null) { 454 throw new Exception(String.format(M3UAOAMMessages.ADD_ASP_TO_AS_FAIL_NO_AS, asName)); 455 } 456 457 Asp asp = as.removeAppServerProcess(aspName); 458 asp.getAspFactory().destroyAsp(asp); 459 this.store(); 460 return asp; 461 } 462 463 /** 464 * This method should be called by management to start the ASP 465 * 466 * @param aspName 467 * The name of the ASP to be started 468 * @throws Exception 469 */ 470 public void startAsp(String aspName) throws Exception { 471 AspFactory aspFactory = this.getAspFactory(aspName); 472 473 if (aspFactory == null) { 474 throw new Exception(String.format("No ASP found by name=%s", aspName)); 475 } 476 477 if (aspFactory.getStatus()) { 478 throw new Exception(String.format("ASP name=%s already started", aspName)); 479 } 480 481 if (aspFactory.getAspList().size() == 0) { 482 throw new Exception(String.format("ASP name=%s not assigned to any AS yet", aspName)); 483 } 484 485 aspFactory.start(); 486 this.store(); 487 } 488 489 /** 490 * This method should be called by management to stop the ASP 491 * 492 * @param aspName 493 * The name of the ASP to be stopped 494 * @throws Exception 495 */ 496 public void stopAsp(String aspName) throws Exception { 497 AspFactory aspFactory = this.getAspFactory(aspName); 498 499 if (aspFactory == null) { 500 throw new Exception(String.format("No ASP found by name=%s", aspName)); 501 } 502 503 if (!aspFactory.getStatus()) { 504 throw new Exception(String.format("ASP name=%s already stopped", aspName)); 505 } 506 507 aspFactory.stop(); 508 this.store(); 509 } 510 511 public void addRoute(int dpc, int opc, int si, String asName) throws Exception { 512 this.routeManagement.addRoute(dpc, opc, si, asName); 513 } 514 515 public void removeRoute(int dpc, int opc, int si, String asName) throws Exception { 516 this.routeManagement.removeRoute(dpc, opc, si, asName); 517 } 518 519 public void sendTransferMessageToLocalUser(Mtp3TransferPrimitive msg, int seqControl) { 520 super.sendTransferMessageToLocalUser(msg, seqControl); 521 } 522 523 public void sendPauseMessageToLocalUser(Mtp3PausePrimitive msg) { 524 super.sendPauseMessageToLocalUser(msg); 525 } 526 527 public void sendResumeMessageToLocalUser(Mtp3ResumePrimitive msg) { 528 super.sendResumeMessageToLocalUser(msg); 529 } 530 531 public void sendStatusMessageToLocalUser(Mtp3StatusPrimitive msg) { 532 super.sendStatusMessageToLocalUser(msg); 533 } 534 535 private AspFactory getAspFactory(String aspName) { 536 for (FastList.Node<AspFactory> n = aspfactories.head(), end = aspfactories.tail(); (n = n.getNext()) != end;) { 537 AspFactory aspFactory = n.getValue(); 538 if (aspFactory.getName().equals(aspName)) { 539 return aspFactory; 540 } 541 } 542 return null; 543 } 544 545 /** 546 * Persist 547 */ 548 public void store() { 549 550 // TODO : Should we keep reference to Objects rather than recreating 551 // everytime? 552 try { 553 XMLObjectWriter writer = XMLObjectWriter.newInstance(new FileOutputStream(persistFile.toString())); 554 writer.setBinding(binding); 555 // Enables cross-references. 556 // writer.setReferenceResolver(new XMLReferenceResolver()); 557 writer.setIndentation(TAB_INDENT); 558 writer.write(aspfactories, ASP_FACTORY_LIST, FastList.class); 559 writer.write(appServers, AS_LIST, FastList.class); 560 writer.write(this.routeManagement.route, DPC_VS_AS_LIST, RouteMap.class); 561 562 writer.close(); 563 } catch (Exception e) { 564 logger.error("Error while persisting the Rule state in file", e); 565 } 566 } 567 568 /** 569 * Load and create LinkSets and Link from persisted file 570 * 571 * @throws Exception 572 */ 573 public void load() throws FileNotFoundException { 574 575 XMLObjectReader reader = null; 576 try { 577 reader = XMLObjectReader.newInstance(new FileInputStream(persistFile.toString())); 578 579 reader.setBinding(binding); 580 aspfactories = reader.read(ASP_FACTORY_LIST, FastList.class); 581 appServers = reader.read(AS_LIST, FastList.class); 582 this.routeManagement.route = reader.read(DPC_VS_AS_LIST, RouteMap.class); 583 584 // Create Asp's and assign to each of the AS. Schedule the FSM's 585 for (FastList.Node<As> n = appServers.head(), end = appServers.tail(); (n = n.getNext()) != end;) { 586 As as = n.getValue(); 587 as.setM3UAManagement(this); 588 FSM asLocalFSM = as.getLocalFSM(); 589 m3uaScheduler.execute(asLocalFSM); 590 591 FSM asPeerFSM = as.getPeerFSM(); 592 m3uaScheduler.execute(asPeerFSM); 593 594 // All the Asp's for this As added in temp list 595 FastList<Asp> tempAsp = new FastList<Asp>(); 596 tempAsp.addAll(as.getAspList()); 597 598 // Claer Asp's from this As 599 as.getAspList().clear(); 600 601 for (FastList.Node<Asp> n1 = tempAsp.head(), end1 = tempAsp.tail(); (n1 = n1.getNext()) != end1;) { 602 Asp asp = n1.getValue(); 603 604 try { 605 // Now let the Asp's be created from respective 606 // AspFactory and added to As 607 this.assignAspToAs(as.getName(), asp.getName()); 608 } catch (Exception e) { 609 logger.error("Error while assigning Asp to As on loading from xml file", e); 610 } 611 } 612 } 613 614 // Set the transportManagement 615 for (FastList.Node<AspFactory> n = aspfactories.head(), end = aspfactories.tail(); (n = n.getNext()) != end;) { 616 AspFactory factory = n.getValue(); 617 factory.setTransportManagement(this.transportManagement); 618 try { 619 factory.setAssociation(this.transportManagement.getAssociation(factory.associationName)); 620 } catch (Exception e1) { 621 logger.error(String.format( 622 "Error setting Assciation=%s for the AspFactory=%s while loading from XML", 623 factory.associationName, factory.getName()), e1); 624 } 625 626 if (factory.getStatus()) { 627 try { 628 factory.start(); 629 } catch (Exception e) { 630 logger.error( 631 String.format("Error starting the AspFactory=%s while loading from XML", 632 factory.getName()), e); 633 } 634 } 635 } 636 637 } catch (XMLStreamException ex) { 638 // this.logger.info( 639 // "Error while re-creating Linksets from persisted file", ex); 640 } 641 } 642 643 @Override 644 public void sendMessage(Mtp3TransferPrimitive mtp3TransferPrimitive) throws IOException { 645 ProtocolData data = this.parameterFactory.createProtocolData(mtp3TransferPrimitive); 646 PayloadData payload = (PayloadData) messageFactory.createMessage(MessageClass.TRANSFER_MESSAGES, 647 MessageType.PAYLOAD); 648 payload.setData(data); 649 650 As as = this.routeManagement.getAsForRoute(data.getDpc(), data.getOpc(), data.getSI(), data.getSLS()); 651 if (as == null) { 652 logger.error(String.format("Tx : No AS found for routing message %s", payload)); 653 return; 654 } 655 payload.setNetworkAppearance(as.getNetworkAppearance()); 656 payload.setRoutingContext(as.getRoutingContext()); 657 as.write(payload); 658 } 659}