/** * Constructor. * * @param session Session object for this service * @param urlname URLName object to be used for this service */ protected Service(Session session, URLName urlname) { this.session = session; debug = session.getDebug(); url = urlname; /* * Initialize the URLName with default values. * The URLName will be updated when connect is called. */ String protocol = null; String host = null; int port = -1; String user = null; String password = null; String file = null; // get whatever information we can from the URL // XXX - url should always be non-null here, Session // passes it into the constructor if (url != null) { protocol = url.getProtocol(); host = url.getHost(); port = url.getPort(); user = url.getUsername(); password = url.getPassword(); file = url.getFile(); } // try to get protocol-specific default properties if (protocol != null) { if (host == null) host = session.getProperty("mail." + protocol + ".host"); if (user == null) user = session.getProperty("mail." + protocol + ".user"); } // try to get mail-wide default properties if (host == null) host = session.getProperty("mail.host"); if (user == null) user = session.getProperty("mail.user"); // try using the system username if (user == null) { try { user = System.getProperty("user.name"); } catch (SecurityException sex) { // XXX - it's not worth creating a MailLogger just for this // logger.log(Level.CONFIG, "Can't get user.name property", sex); } } url = new URLName(protocol, host, port, file, user, password); // create or choose the appropriate event queue String scope = session.getProperties().getProperty("mail.event.scope", "folder"); Executor executor = (Executor) session.getProperties().get("mail.event.executor"); if (scope.equalsIgnoreCase("application")) q = EventQueue.getApplicationEventQueue(executor); else if (scope.equalsIgnoreCase("session")) q = session.getEventQueue(); else // if (scope.equalsIgnoreCase("store") || // scope.equalsIgnoreCase("folder")) q = new EventQueue(executor); }
/** * Add the event and vector of listeners to the queue to be delivered. * * @param event the event * @param vector the vector of listeners */ protected void queueEvent(MailEvent event, Vector vector) { /* * Copy the vector in order to freeze the state of the set * of EventListeners the event should be delivered to prior * to delivery. This ensures that any changes made to the * Vector from a target listener's method during the delivery * of this event will not take effect until after the event is * delivered. */ Vector v = (Vector) vector.clone(); q.enqueue(event, v); }
/** * Notify all ConnectionListeners. Service implementations are expected to use this method to * broadcast connection events. * * <p>The provided default implementation queues the event into an internal event queue. An event * dispatcher thread dequeues events from the queue and dispatches them to the registered * ConnectionListeners. Note that the event dispatching occurs in a separate thread, thus avoiding * potential deadlock problems. * * @param type the ConnectionEvent type */ protected void notifyConnectionListeners(int type) { /* * Don't bother queuing an event if there's no listeners. * Yes, listeners could be removed after checking, which * just makes this an expensive no-op. */ if (connectionListeners.size() > 0) { ConnectionEvent e = new ConnectionEvent(this, type); queueEvent(e, connectionListeners); } /* Fix for broken JDK1.1.x Garbage collector : * The 'conservative' GC in JDK1.1.x occasionally fails to * garbage-collect Threads which are in the wait state. * This would result in thread (and consequently memory) leaks. * * We attempt to fix this by sending a 'terminator' event * to the queue, after we've sent the CLOSED event. The * terminator event causes the event-dispatching thread to * self destruct. */ if (type == ConnectionEvent.CLOSED) q.terminateQueue(); }
/** Stop the event dispatcher thread so the queue can be garbage collected. */ protected void finalize() throws Throwable { super.finalize(); q.terminateQueue(); }