public SipStackImpl(Properties configurationProperties) throws PeerUnavailableException { this(); String address = configurationProperties .getProperty("javax.sip.IP_ADDRESS"); try {  if (address != null) {    super.setHostAddress(address);  } } catch (java.net.UnknownHostException ex) { throw new PeerUnavailableException("bad address " + address); }   String name = configurationProperties .getProperty("javax.sip.STACK_NAME"); if (name == null) throw new PeerUnavailableException("stack name is missing"); super.setStackName(name);  this.logWriter = new LogWriter(configurationProperties);   this.serverLog = new ServerLog(this, configurationProperties);     this.defaultRouter = new DefaultRouter(this, outboundProxy);   String routerPath = configurationProperties .getProperty("javax.sip.ROUTER_PATH"); if (routerPath == null) routerPath = "gov.nist.javax.sip.stack.DefaultRouter"; String outboundProxy = configurationProperties .getProperty("javax.sip.OUTBOUND_PROXY");  try { Class routerClass = Class.forName(routerPath); Class[] constructorArgs = new Class[2]; constructorArgs[0] = javax.sip.SipStack.class; constructorArgs[1] = String.class; Constructor cons = routerClass.getConstructor(constructorArgs); Object[] args = new Object[2]; args[0] = (SipStack) this; args[1] = outboundProxy; Router router = (Router) cons.newInstance(args); super.setRouter(router); } catch (InvocationTargetException ex1) { getLogWriter() .logError( "could not instantiate router -- invocation target problem", (Exception) ex1.getCause()); throw new PeerUnavailableException( "Cound not instantiate router - check constructor", ex1); } catch (Exception ex) { getLogWriter().logError("could not instantiate router", (Exception) ex.getCause()); throw new PeerUnavailableException("Could not instantiate router", ex); }   String useRouterForAll = configurationProperties .getProperty("javax.sip.USE_ROUTER_FOR_ALL_URIS"); this.useRouterForAll = true; if (useRouterForAll != null) { this.useRouterForAll = "true".equalsIgnoreCase(useRouterForAll); }   String extensionMethods = configurationProperties .getProperty("javax.sip.EXTENSION_METHODS");  if (extensionMethods != null) { java.util.StringTokenizer st = new java.util.StringTokenizer( extensionMethods); while (st.hasMoreTokens()) { String em = st.nextToken(":"); if (em.equalsIgnoreCase(Request.BYE) || em.equalsIgnoreCase(Request.INVITE) || em.equalsIgnoreCase(Request.SUBSCRIBE) || em.equalsIgnoreCase(Request.NOTIFY) || em.equalsIgnoreCase(Request.ACK) || em.equalsIgnoreCase(Request.OPTIONS)) throw new PeerUnavailableException("Bad extension method " + em); else this.addExtensionMethod(em); } }   super.isAutomaticDialogSupportEnabled = configurationProperties .getProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "on") .equalsIgnoreCase("on");  this.deliverTerminatedEventForAck = configurationProperties.getProperty ("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_ACK", "false").equalsIgnoreCase("true");  this.deliverUnsolicitedNotify = configurationProperties.getProperty ("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "false").equalsIgnoreCase("true");   String forkedSubscriptions = configurationProperties .getProperty("javax.sip.FORKABLE_EVENTS"); if (forkedSubscriptions != null) { StringTokenizer st = new StringTokenizer(forkedSubscriptions); while (st.hasMoreTokens()) { String nextEvent = st.nextToken(); this.forkedEvents.add(nextEvent); } }      final String NETWORK_LAYER_KEY = "gov.nist.javax.sip.NETWORK_LAYER";  if (configurationProperties.containsKey(NETWORK_LAYER_KEY)) { String path = configurationProperties .getProperty(NETWORK_LAYER_KEY); try { Class clazz = Class.forName(path); Constructor c = clazz.getConstructor(new Class[0]); networkLayer = (NetworkLayer) c.newInstance(new Object[0]); } catch (Exception e) { throw new PeerUnavailableException( "can't find or instantiate NetworkLayer implementation: " + path); } }  final String ADDRESS_RESOLVER_KEY = "gov.nist.javax.sip.ADDRESS_RESOLVER";  if (configurationProperties.containsKey(ADDRESS_RESOLVER_KEY)) { String path = configurationProperties .getProperty(ADDRESS_RESOLVER_KEY); try { Class clazz = Class.forName(path); Constructor c = clazz.getConstructor(new Class[0]); this.addressResolver = (AddressResolver) c.newInstance(new Object[0]); } catch (Exception e) { throw new PeerUnavailableException( "can't find or instantiate AddressResolver implementation: " + path); } }  String maxConnections = configurationProperties .getProperty("gov.nist.javax.sip.MAX_CONNECTIONS"); if (maxConnections != null) { try { this.maxConnections = new Integer(maxConnections).intValue(); } catch (NumberFormatException ex) { System.out.println("max connections - bad value " + ex.getMessage()); } }  String threadPoolSize = configurationProperties .getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE"); if (threadPoolSize != null) { try { this.threadPoolSize = new Integer(threadPoolSize).intValue(); } catch (NumberFormatException ex) { System.out.println("thread pool size - bad value " + ex.getMessage()); } }  String transactionTableSize = configurationProperties .getProperty("gov.nist.javax.sip.MAX_SERVER_TRANSACTIONS"); if (transactionTableSize != null) { try { this.serverTransactionTableHighwaterMark = new Integer( transactionTableSize).intValue(); this.serverTransactionTableLowaterMark = this.serverTransactionTableHighwaterMark * 80 / 100;  } catch (NumberFormatException ex) { System.out.println("transaction table size - bad value " + ex.getMessage()); } }  super.cacheServerConnections = true; String flag = configurationProperties .getProperty("gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS");  if (flag != null && "false".equalsIgnoreCase(flag.trim())) { super.cacheServerConnections = false; }  super.cacheClientConnections = true; String cacheflag = configurationProperties .getProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS");  if (cacheflag != null && "false".equalsIgnoreCase(cacheflag.trim())) { super.cacheClientConnections = false; }  String readTimeout = configurationProperties .getProperty("gov.nist.javax.sip.READ_TIMEOUT"); if (readTimeout != null) { try {  int rt = Integer.parseInt(readTimeout); if (rt >= 100) { super.readTimeout = rt; } else { System.out.println("Value too low " + readTimeout); } } catch (NumberFormatException nfe) {  System.out.println("Bad read timeout " + readTimeout); } }    String stunAddr = configurationProperties .getProperty("gov.nist.javax.sip.STUN_SERVER");  if (stunAddr != null) this.logWriter.logWarning("Ignoring obsolete property " + "gov.nist.javax.sip.STUN_SERVER");  String maxMsgSize = configurationProperties .getProperty("gov.nist.javax.sip.MAX_MESSAGE_SIZE");  try { if (maxMsgSize != null) { super.maxMessageSize = new Integer(maxMsgSize).intValue(); if (super.maxMessageSize < 4096) super.maxMessageSize = 4096; } else {  super.maxMessageSize = 0; } } catch (NumberFormatException ex) { System.out.println("maxMessageSize - bad value " + ex.getMessage()); }  String rel = configurationProperties .getProperty("gov.nist.javax.sip.REENTRANT_LISTENER"); this.reEntrantListener = (rel != null && "true".equalsIgnoreCase(rel));   this.non2XXAckPassedToListener = Boolean .valueOf( configurationProperties .getProperty( "gov.nist.javax.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER", "false")).booleanValue();
protected SipStackImpl() { super(); NistSipMessageFactoryImpl msgFactory = new NistSipMessageFactoryImpl( this); super.setMessageFactory(msgFactory); this.eventScanner = new EventScanner(this); this.listeningPoints = new Hashtable(); this.sipProviders = new LinkedList();
	public SipStackImpl(Properties configurationProperties)			throws PeerUnavailableException {		this();		String address = configurationProperties				.getProperty("javax.sip.IP_ADDRESS");		try {			/** Retrieve the stack IP address */			if (address != null) {				// In version 1.2 of the spec the IP address is				// associated with the listening point and				// is not madatory.				super.setHostAddress(address);			}		} catch (java.net.UnknownHostException ex) {			throw new PeerUnavailableException("bad address " + address);		}		/** Retrieve the stack name */		String name = configurationProperties				.getProperty("javax.sip.STACK_NAME");		if (name == null)			throw new PeerUnavailableException("stack name is missing");		super.setStackName(name);		// To log debug messages.		this.logWriter = new LogWriter(configurationProperties);		// Server log file.		this.serverLog = new ServerLog(this, configurationProperties);		// Default router -- use this for routing SIP URIs.		// Our router does not do DNS lookups.		this.defaultRouter = new DefaultRouter(this, outboundProxy);		/** Retrieve the router path */		String routerPath = configurationProperties				.getProperty("javax.sip.ROUTER_PATH");		if (routerPath == null)			routerPath = "gov.nist.javax.sip.stack.DefaultRouter";		String outboundProxy = configurationProperties				.getProperty("javax.sip.OUTBOUND_PROXY");		try {			Class routerClass = Class.forName(routerPath);			Class[] constructorArgs = new Class[2];			constructorArgs[0] = javax.sip.SipStack.class;			constructorArgs[1] = String.class;			Constructor cons = routerClass.getConstructor(constructorArgs);			Object[] args = new Object[2];			args[0] = (SipStack) this;			args[1] = outboundProxy;			Router router = (Router) cons.newInstance(args);			super.setRouter(router);		} catch (InvocationTargetException ex1) {			getLogWriter()					.logError(							"could not instantiate router -- invocation target problem",							(Exception) ex1.getCause());			throw new PeerUnavailableException(					"Cound not instantiate router - check constructor", ex1);		} catch (Exception ex) {			getLogWriter().logError("could not instantiate router",					(Exception) ex.getCause());			throw new PeerUnavailableException("Could not instantiate router",					ex);		}		// The flag that indicates that the default router is to be ignored.		String useRouterForAll = configurationProperties				.getProperty("javax.sip.USE_ROUTER_FOR_ALL_URIS");		this.useRouterForAll = true;		if (useRouterForAll != null) {			this.useRouterForAll = "true".equalsIgnoreCase(useRouterForAll);		}		/*		 * Retrieve the EXTENSION Methods. These are used for instantiation of		 * Dialogs.		 */		String extensionMethods = configurationProperties				.getProperty("javax.sip.EXTENSION_METHODS");		if (extensionMethods != null) {			java.util.StringTokenizer st = new java.util.StringTokenizer(					extensionMethods);			while (st.hasMoreTokens()) {				String em = st.nextToken(":");				if (em.equalsIgnoreCase(Request.BYE)						|| em.equalsIgnoreCase(Request.INVITE)						|| em.equalsIgnoreCase(Request.SUBSCRIBE)						|| em.equalsIgnoreCase(Request.NOTIFY)						|| em.equalsIgnoreCase(Request.ACK)						|| em.equalsIgnoreCase(Request.OPTIONS))					throw new PeerUnavailableException("Bad extension method "							+ em);				else					this.addExtensionMethod(em);			}		}		// Set the auto dialog support flag.		super.isAutomaticDialogSupportEnabled = configurationProperties				.getProperty("javax.sip.AUTOMATIC_DIALOG_SUPPORT", "on")				.equalsIgnoreCase("on");				this.deliverTerminatedEventForAck = configurationProperties.getProperty		("gov.nist.javax.sip.DELIVER_TERMINATED_EVENT_FOR_ACK", "false").equalsIgnoreCase("true");		this.deliverUnsolicitedNotify = configurationProperties.getProperty		("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "false").equalsIgnoreCase("true");				String forkedSubscriptions = configurationProperties				.getProperty("javax.sip.FORKABLE_EVENTS");		if (forkedSubscriptions != null) {			StringTokenizer st = new StringTokenizer(forkedSubscriptions);			while (st.hasMoreTokens()) {				String nextEvent = st.nextToken();				this.forkedEvents.add(nextEvent);			}		}		// The following features are unique to the NIST implementation.		/*		 * gets the NetworkLayer implementation, if any. Note that this is a		 * NIST only feature.		 */		final String NETWORK_LAYER_KEY = "gov.nist.javax.sip.NETWORK_LAYER";		if (configurationProperties.containsKey(NETWORK_LAYER_KEY)) {			String path = configurationProperties					.getProperty(NETWORK_LAYER_KEY);			try {				Class clazz = Class.forName(path);				Constructor c = clazz.getConstructor(new Class[0]);				networkLayer = (NetworkLayer) c.newInstance(new Object[0]);			} catch (Exception e) {				throw new PeerUnavailableException(						"can't find or instantiate NetworkLayer implementation: "								+ path);			}		}		final String ADDRESS_RESOLVER_KEY = "gov.nist.javax.sip.ADDRESS_RESOLVER";		if (configurationProperties.containsKey(ADDRESS_RESOLVER_KEY)) {			String path = configurationProperties					.getProperty(ADDRESS_RESOLVER_KEY);			try {				Class clazz = Class.forName(path);				Constructor c = clazz.getConstructor(new Class[0]);				this.addressResolver = (AddressResolver) c.newInstance(new Object[0]);			} catch (Exception e) {				throw new PeerUnavailableException(						"can't find or instantiate AddressResolver implementation: "								+ path);			}		}		String maxConnections = configurationProperties				.getProperty("gov.nist.javax.sip.MAX_CONNECTIONS");		if (maxConnections != null) {			try {				this.maxConnections = new Integer(maxConnections).intValue();			} catch (NumberFormatException ex) {				System.out.println("max connections - bad value "						+ ex.getMessage());			}		}		String threadPoolSize = configurationProperties				.getProperty("gov.nist.javax.sip.THREAD_POOL_SIZE");		if (threadPoolSize != null) {			try {				this.threadPoolSize = new Integer(threadPoolSize).intValue();			} catch (NumberFormatException ex) {				System.out.println("thread pool size - bad value "						+ ex.getMessage());			}		}		String transactionTableSize = configurationProperties				.getProperty("gov.nist.javax.sip.MAX_SERVER_TRANSACTIONS");		if (transactionTableSize != null) {			try {				this.serverTransactionTableHighwaterMark = new Integer(						transactionTableSize).intValue();				this.serverTransactionTableLowaterMark = this.serverTransactionTableHighwaterMark * 80 / 100;				// Lowater is 80% of highwater			} catch (NumberFormatException ex) {				System.out.println("transaction table size - bad value "						+ ex.getMessage());			}		}		super.cacheServerConnections = true;		String flag = configurationProperties				.getProperty("gov.nist.javax.sip.CACHE_SERVER_CONNECTIONS");		if (flag != null && "false".equalsIgnoreCase(flag.trim())) {			super.cacheServerConnections = false;		}		super.cacheClientConnections = true;		String cacheflag = configurationProperties				.getProperty("gov.nist.javax.sip.CACHE_CLIENT_CONNECTIONS");		if (cacheflag != null && "false".equalsIgnoreCase(cacheflag.trim())) {			super.cacheClientConnections = false;		}		String readTimeout = configurationProperties				.getProperty("gov.nist.javax.sip.READ_TIMEOUT");		if (readTimeout != null) {			try {				int rt = Integer.parseInt(readTimeout);				if (rt >= 100) {					super.readTimeout = rt;				} else {					System.out.println("Value too low " + readTimeout);				}			} catch (NumberFormatException nfe) {				// Ignore.				System.out.println("Bad read timeout " + readTimeout);			}		}		// Get the address of the stun server.		String stunAddr = configurationProperties				.getProperty("gov.nist.javax.sip.STUN_SERVER");		if (stunAddr != null)			this.logWriter.logWarning("Ignoring obsolete property "					+ "gov.nist.javax.sip.STUN_SERVER");		String maxMsgSize = configurationProperties				.getProperty("gov.nist.javax.sip.MAX_MESSAGE_SIZE");		try {			if (maxMsgSize != null) {				super.maxMessageSize = new Integer(maxMsgSize).intValue();				if (super.maxMessageSize < 4096)					super.maxMessageSize = 4096;			} else {				// Allow for "infinite" size of message				super.maxMessageSize = 0;			}		} catch (NumberFormatException ex) {			System.out.println("maxMessageSize - bad value " + ex.getMessage());		}		String rel = configurationProperties				.getProperty("gov.nist.javax.sip.REENTRANT_LISTENER");		this.reEntrantListener = (rel != null && "true".equalsIgnoreCase(rel));		// JvB: added property for testing		this.non2XXAckPassedToListener = Boolean				.valueOf(						configurationProperties								.getProperty(										"gov.nist.javax.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER",										"false")).booleanValue();	}