001: /**
002: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
003: * Unpublished - rights reserved under the Copyright Laws of the United States.
004: * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
005: * Copyright © 2005 BEA Systems, Inc. All rights reserved.
006: *
007: * Use is subject to license terms.
008: *
009: * This distribution may include materials developed by third parties.
010: *
011: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
012: *
013: * Module Name : JSIP Specification
014: * File Name : SipFactory.java
015: * Author : Phelim O'Doherty
016: *
017: * HISTORY
018: * Version Date Author Comments
019: * 1.1 08/10/2002 Phelim O'Doherty
020: * 1.2 20/12/2005 Phelim O'Doherty Modified to enable single stack
021: * instance if no IP Address config
022: * property.
023: *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
024: */package javax.sip;
025:
026: import javax.sip.address.AddressFactory;
027: import javax.sip.message.MessageFactory;
028: import javax.sip.header.HeaderFactory;
029: import java.util.*;
030: import java.lang.reflect.Constructor;
031:
032: /**
033: * The SipFactory is a singleton class which applications can use a single
034: * access point to obtain proprietary implementations of this specification. As
035: * the SipFactory is a singleton class there will only ever be one instance of
036: * the SipFactory. The single instance of the SipFactory can be obtained using
037: * the {@link SipFactory#getInstance()} method. If an instance of the SipFactory
038: * already exists it will be returned to the application, otherwise a new
039: * instance will be created. A peer implementation object can be obtained from
040: * the SipFactory by invoking the appropriate create method on the SipFactory
041: * e.g. to create a peer SipStack, an application would invoke the
042: * {@link SipFactory#createSipStack(Properties)} method.
043: * <p>
044: * <b>Naming Convention</b><br>
045: * Note that the SipFactory utilises a naming convention defined by this
046: * specification to identify the location of proprietary objects that implement
047: * this specification. The naming convention is defined as follows:
048: * <ul>
049: * <li>The <b>upper-level package structure</b> referred to by the SipFactory
050: * with the attribute <var>pathname</var> can be used to differentiate between
051: * proprietary implementations from different SIP stack vendors. The
052: * <var>pathname</var> used by each SIP vendor <B>must be</B> the domain name
053: * assigned to that vendor in reverse order. For example, the pathname used by
054: * Sun Microsystem's would be <code>com.sun</code>.
055: * <li>The <b>lower-level package structure and classname</b> of a peer object
056: * is also mandated by this specification. The lowel-level package must be
057: * identical to the package structure defined by this specification and the
058: * classname is mandated to the interface name appended with the
059: * <code>Impl</code> post-fix. For example, the lower-level package structure
060: * and classname of a proprietary implementation of the
061: * <code>javax.sip.SipStack</code> interface <B>must</B> be
062: * <code>javax.sip.SipStackImpl</code>.
063: * </ul>
064: *
065: * Using this naming convention the SipFactory can locate a vendor's
066: * implementation of this specification without requiring an application to
067: * supply a user defined string to each create method in the SipFactory. Instead
068: * an application merely needs to identify the vendors SIP implementation it
069: * would like to use by setting the pathname of that vendors implementation.
070: * <p>
071: * It follows that a proprietary implementation of a peer object of this
072: * specification can be located at:
073: * <p>
074: * <code>'pathname'.'lower-level package structure and classname'.</code>
075: * <p>
076: * For example an application can use the SipFactory to instantiate a NIST
077: * peer SipStack object by setting the pathname to
078: * <code>gov.nist</code> and calling the createSipStack method. The SipFactory
079: * would return a new instance of the SipStack object at the following location:
080: * <code>gov.nist.javax.sip.SipStackImpl.java</code> Because the space of
081: * domain names is managed, this scheme ensures that collisions between two
082: * different vendor's implementations will not happen. For example: a different
083: * vendor with a domain name 'bea.com' would have their peer SipStack object
084: * located at <code>com.bea.javax.sip.SipStackImpl.java</code>.
085: * <p>
086: * <b>Default Namespace:</b><br>
087: * This specification defines a default namespace for the SipFactory, this
088: * namespace is the location of the Reference Implementation. The default
089: * namespace is <code>gov.nist</code> the author of the Reference
090: * Implementation, therefore the <var>pathname</var> will have the initial
091: * value of <code>gov.nist</code> for a new instance of the SipFactory. An
092: * application must set the <var>pathname</var> of the SipFactory on retrieval
093: * of a new instance of the factory in order to use a different vendors SIP
094: * stack from that of the Reference Implementation. An application can not mix
095: * different vendor's peer implementation objects.
096: *
097: * @author BEA Systems, NIST
098: * @version 1.2
099: */
100:
101: public class SipFactory {
102:
103: /**
104: * Returns an instance of a SipFactory. This is a singleton class so this
105: * method is the global access point for the SipFactory.
106: *
107: * @return the single instance of this singleton SipFactory
108: */
109: public synchronized static SipFactory getInstance() {
110: if (myFactory == null) {
111: myFactory = new SipFactory();
112: }
113: return myFactory;
114: }
115:
116: /**
117: * Creates an instance of a SipStack implementation based on the
118: * configuration properties object passed to this method. The
119: * recommended behaviour is to not specify an
120: * "javax.sip.IP_ADDRESS" property in the Properties argument, in this
121: * case the "javax.sip.STACK_NAME" uniquely identifies the stack.
122: * A new stack instance will be returned for each different stack name
123: * associated with a specific vendor implementation. The
124: * ListeningPoint is used to configure the IP Address argument.
125: * For backwards compatability, if a "javax.sip.IP_ADDRESS" is supplied,
126: * this method ensures that only one instance of a SipStack is returned
127: * to the application for that IP Address, independent of the number of
128: * times this method is called. Different SipStack instances are
129: * returned for each different IP address.
130: * <p>
131: * See {@link SipStack} for the expected format of the
132: * <code>properties</code> argument.
133: *
134: * @throws PeerUnavailableException
135: * if the peer class could not be found
136: */
137: public synchronized SipStack createSipStack(Properties properties)
138: throws PeerUnavailableException {
139:
140: String ipAddress = properties
141: .getProperty("javax.sip.IP_ADDRESS");
142: String name = properties.getProperty("javax.sip.STACK_NAME");
143: if (name == null)
144: throw new PeerUnavailableException(
145: "Missing javax.sip.STACK_NAME property");
146: // IP address was not specified in the properties.
147: // This means that the architecture supports a single sip stack
148: // instance per stack name
149: // and each listening point is assinged its own IP address.
150: if (ipAddress == null) {
151: SipStack mySipStack = (SipStack) this .sipStackByName
152: .get(name);
153: if (mySipStack == null) {
154: mySipStack = createStack(properties);
155: }
156: return mySipStack;
157: } else {
158: // Check to see if a stack with that IP Address is already
159: // created, if so select it to be returned. In this case the
160: // the name is not used.
161: int i = 0;
162: for (i = 0; i < sipStackList.size(); i++) {
163: if (((SipStack) sipStackList.get(i)).getIPAddress()
164: .equals(ipAddress)) {
165: return (SipStack) sipStackList.get(i);
166: }
167: }
168: return createStack(properties);
169: }
170:
171: }
172:
173: /**
174: * Creates an instance of the MessageFactory implementation. This method
175: * ensures that only one instance of a MessageFactory is returned to the
176: * application, no matter how often this method is called.
177: *
178: * @throws PeerUnavailableException
179: * if peer class could not be found
180: */
181:
182: public MessageFactory createMessageFactory()
183: throws PeerUnavailableException {
184: if (messageFactory == null) {
185: messageFactory = (MessageFactory) createSipFactory("javax.sip.message.MessageFactoryImpl");
186: }
187: return messageFactory;
188: }
189:
190: /**
191: * Creates an instance of the HeaderFactory implementation. This method
192: * ensures that only one instance of a HeaderFactory is returned to the
193: * application, no matter how often this method is called.
194: *
195: * @throws PeerUnavailableException
196: * if peer class could not be found
197: */
198: public HeaderFactory createHeaderFactory()
199: throws PeerUnavailableException {
200: if (headerFactory == null) {
201: headerFactory = (HeaderFactory) createSipFactory("javax.sip.header.HeaderFactoryImpl");
202: }
203: return headerFactory;
204: }
205:
206: /**
207: * Creates an instance of the AddressFactory implementation. This method
208: * ensures that only one instance of an AddressFactory is returned to the
209: * application, no matter how often this method is called.
210: *
211: * @throws PeerUnavailableException
212: * if peer class could not be found
213: */
214: public AddressFactory createAddressFactory()
215: throws PeerUnavailableException {
216: if (addressFactory == null) {
217: addressFactory = (AddressFactory) createSipFactory("javax.sip.address.AddressFactoryImpl");
218: }
219: return addressFactory;
220: }
221:
222: /**
223: * Sets the <var>pathname</var> that identifies the location of a
224: * particular vendor's implementation of this specification. The
225: * <var>pathname</var> must be the reverse domain name assigned to the
226: * vendor providing the implementation. An application must call
227: * {@link SipFactory#resetFactory()} before changing between different
228: * implementations of this specification.
229: *
230: * @param pathName -
231: * the reverse domain name of the vendor, e.g. Sun Microsystem's
232: * would be 'com.sun'
233: */
234: public void setPathName(String pathName) {
235: this .pathName = pathName;
236: }
237:
238: /**
239: * Returns the current <var>pathname</var> of the SipFactory. The
240: * <var>pathname</var> identifies the location of a particular vendor's
241: * implementation of this specification as defined the naming convention.
242: * The pathname must be the reverse domain name assigned to the vendor
243: * providing this implementation. This value is defaulted to
244: * <code>gov.nist</code> the location of the Reference Implementation.
245: *
246: * @return the string identifying the current vendor implementation.
247: */
248: public String getPathName() {
249: return pathName;
250: }
251:
252: /**
253: * This method reset's the SipFactory's references to the object's it has
254: * created. It allows these objects to be garbage collected assuming the
255: * application no longer holds references to them. This method must be
256: * called to reset the factories references to a specific vendors
257: * implementation of this specification before it creates another vendors
258: * implementation of this specification by changing the <var>pathname</var>
259: * of the SipFactory.
260: */
261: public void resetFactory() {
262: sipStackList.clear();
263: messageFactory = null;
264: headerFactory = null;
265: addressFactory = null;
266: sipStackByName = new Hashtable();
267: pathName = "gov.nist";
268: }
269:
270: /**
271: * Private Utility method used by all create methods to return an instance
272: * of the supplied object.
273: */
274: private Object createSipFactory(String objectClassName)
275: throws PeerUnavailableException {
276:
277: // If the stackClassName is null, then throw an exception
278: if (objectClassName == null) {
279: throw new NullPointerException();
280: }
281: try {
282: Class peerObjectClass = Class.forName(getPathName() + "."
283: + objectClassName);
284:
285: // Creates a new instance of the class represented by this Class
286: // object.
287: Object newPeerObject = peerObjectClass.newInstance();
288: return (newPeerObject);
289: } catch (Exception e) {
290: String errmsg = "The Peer Factory: "
291: + getPathName()
292: + "."
293: + objectClassName
294: + " could not be instantiated. Ensure the Path Name has been set.";
295: throw new PeerUnavailableException(errmsg, e);
296: }
297: }
298:
299: /**
300: * Private Utility method used to create a new SIP Stack instance.
301: */
302: private SipStack createStack(Properties properties)
303: throws PeerUnavailableException {
304: try {
305: // create parameters argument to identify constructor
306: Class[] paramTypes = new Class[1];
307: paramTypes[0] = Class.forName("java.util.Properties");
308: // get constructor of SipStack in order to instantiate
309: Constructor sipStackConstructor = Class.forName(
310: getPathName() + ".javax.sip.SipStackImpl")
311: .getConstructor(paramTypes);
312: // Wrap properties object in order to pass to constructor of
313: // SipSatck
314: Object[] conArgs = new Object[1];
315: conArgs[0] = properties;
316: // Creates a new instance of SipStack Class with the supplied
317: // properties.
318: SipStack sipStack = (SipStack) sipStackConstructor
319: .newInstance(conArgs);
320: sipStackList.add(sipStack);
321: String name = properties
322: .getProperty("javax.sip.STACK_NAME");
323: this .sipStackByName.put(name, sipStack);
324: return sipStack;
325: } catch (Exception e) {
326: String errmsg = "The Peer SIP Stack: "
327: + getPathName()
328: + ".javax.sip.SipStackImpl"
329: + " could not be instantiated. Ensure the Path Name has been set.";
330: throw new PeerUnavailableException(errmsg, e);
331: }
332: }
333:
334: /**
335: * Constructor for SipFactory class. This is private because applications
336: * are not permitted to create an instance of the SipFactory using "new".
337: */
338: private SipFactory() {
339: this .sipStackByName = new Hashtable();
340: }
341:
342: // default domain to locate Reference Implementation
343: private String pathName = "gov.nist";
344:
345: // My sip stack. The implementation will allow only a single
346: // sip stack in future versions of this specification.
347:
348: private Hashtable sipStackByName;
349:
350: // intrenal variable to ensure SipFactory only returns a single instance
351: // of the other Factories and SipStack
352: private MessageFactory messageFactory = null;
353:
354: private HeaderFactory headerFactory = null;
355:
356: private AddressFactory addressFactory = null;
357:
358: private static SipFactory myFactory = null;
359:
360: // This is for backwards compatibility with
361: // version 1.1
362:
363: private final LinkedList sipStackList = new LinkedList();
364:
365: }
|