0001: /*
0002: License $Id: Service.java,v 1.4 2003/09/13 04:59:56 hendriks73 Exp $
0003:
0004: Copyright (c) 2001-2005 tagtraum industries.
0005:
0006: LGPL
0007: ====
0008:
0009: jo! is free software; you can redistribute it and/or
0010: modify it under the terms of the GNU Lesser General Public
0011: License as published by the Free Software Foundation; either
0012: version 2.1 of the License, or (at your option) any later version.
0013:
0014: jo! is distributed in the hope that it will be useful,
0015: but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0017: Lesser General Public License for more details.
0018:
0019: You should have received a copy of the GNU Lesser General Public
0020: License along with this library; if not, write to the Free Software
0021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0022:
0023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
0024:
0025:
0026: Sun license
0027: ===========
0028:
0029: This release contains software by Sun Microsystems. Therefore
0030: the following conditions have to be met, too. They apply to the
0031: files
0032:
0033: - lib/mail.jar
0034: - lib/activation.jar
0035: - lib/jsse.jar
0036: - lib/jcert.jar
0037: - lib/jaxp.jar
0038: - lib/crimson.jar
0039: - lib/servlet.jar
0040: - lib/jnet.jar
0041: - lib/jaas.jar
0042: - lib/jaasmod.jar
0043:
0044: contained in this release.
0045:
0046: a. Licensee may not modify the Java Platform
0047: Interface (JPI, identified as classes contained within the javax
0048: package or any subpackages of the javax package), by creating additional
0049: classes within the JPI or otherwise causing the addition to or modification
0050: of the classes in the JPI. In the event that Licensee creates any
0051: Java-related API and distribute such API to others for applet or
0052: application development, you must promptly publish broadly, an accurate
0053: specification for such API for free use by all developers of Java-based
0054: software.
0055:
0056: b. Software is confidential copyrighted information of Sun and
0057: title to all copies is retained by Sun and/or its licensors. Licensee
0058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
0059: reverse engineer Software. Software may not be leased, assigned, or
0060: sublicensed, in whole or in part. Software is not designed or intended
0061: for use in on-line control of aircraft, air traffic, aircraft navigation
0062: or aircraft communications; or in the design, construction, operation or
0063: maintenance of any nuclear facility. Licensee warrants that it will not
0064: use or redistribute the Software for such purposes.
0065:
0066: c. Software is provided "AS IS," without a warranty
0067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
0068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
0069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
0070:
0071: d. This License is effective until terminated. Licensee may
0072: terminate this License at any time by destroying all copies of Software.
0073: This License will terminate immediately without notice from Sun if Licensee
0074: fails to comply with any provision of this License. Upon such termination,
0075: Licensee must destroy all copies of Software.
0076:
0077: e. Software, including technical data, is subject to U.S.
0078: export control laws, including the U.S. Export Administration Act and its
0079: associated regulations, and may be subject to export or import regulations
0080: in other countries. Licensee agrees to comply strictly with all such
0081: regulations and acknowledges that it has the responsibility to obtain
0082: licenses to export, re-export, or import Software. Software may not be
0083: downloaded, or otherwise exported or re-exported (i) into, or to a national
0084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
0085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
0086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
0087: Commerce Department's Table of Denial Orders.
0088:
0089:
0090: Feedback
0091: ========
0092:
0093: We encourage your feedback and suggestions and want to use your feedback to
0094: improve the Software. Send all such feedback to:
0095: <feedback@tagtraum.com>
0096:
0097: For more information on tagtraum industries and jo!
0098: please see <http://www.tagtraum.com/>.
0099:
0100:
0101: */
0102: package com.tagtraum.framework.server;
0103:
0104: import com.tagtraum.framework.log.C_Log;
0105: import com.tagtraum.framework.log.Log;
0106: import com.tagtraum.framework.util.Factory;
0107: import com.tagtraum.framework.util.UnSyncStringBuffer;
0108:
0109: import java.io.Serializable;
0110: import java.lang.reflect.Constructor;
0111: import java.util.Enumeration;
0112: import java.util.Hashtable;
0113:
0114: /**
0115: * A <code>Service</code>-implementation.
0116: *
0117: * @author <a href="mailto:hs@tagtraum.com">Hendrik Schreiber</a>
0118: * @version 1.1beta1 $Id: Service.java,v 1.4 2003/09/13 04:59:56 hendriks73 Exp $
0119: * @see com.tagtraum.metaserver.MetaServer
0120: * @see TCPService
0121: * @see UDPService
0122: */
0123: public abstract class Service implements Serializable, I_Service,
0124: C_Service {
0125:
0126: /**
0127: * Source-Version
0128: */
0129: public static String vcid = "$Id: Service.java,v 1.4 2003/09/13 04:59:56 hendriks73 Exp $";
0130:
0131: /**
0132: * Socket Timeout.
0133: */
0134: protected int mySoTimeout;
0135:
0136: /**
0137: * The Handlers classname.
0138: */
0139: protected String myHandlerClassname;
0140:
0141: /**
0142: * Attributes.
0143: */
0144: protected Hashtable myAttributes;
0145:
0146: /**
0147: * Handler ThreadGroup.
0148: */
0149: transient protected ThreadGroup myThreadGroup;
0150:
0151: /**
0152: * Listeners.
0153: */
0154: transient protected Hashtable myListeners;
0155:
0156: /**
0157: * Flag that indicates whether this <code>Service</code> should be stopped.
0158: */
0159: transient protected boolean stopped;
0160:
0161: /**
0162: * The <code>Service</code>'s name.
0163: */
0164: protected String myName;
0165:
0166: /**
0167: * Minor version number.
0168: */
0169: protected int myMinorVersion;
0170:
0171: /**
0172: * Major version number.
0173: */
0174: protected int myMajorVersion;
0175:
0176: /**
0177: * Minimum number of HandlerThreads.
0178: */
0179: protected int minHandlers;
0180:
0181: /**
0182: * Maximum number of HandlerThreads.
0183: */
0184: protected int maxHandlers;
0185:
0186: /**
0187: * Handler factory.
0188: */
0189: protected Factory myFactory;
0190:
0191: /**
0192: * Alive flag.
0193: */
0194: protected boolean myAlive;
0195:
0196: /**
0197: * Running since.
0198: */
0199: protected long myRunningSince;
0200:
0201: /**
0202: *
0203: */
0204: protected Object[] myHandlerConstructorArgs;
0205:
0206: /**
0207: *
0208: */
0209: protected Constructor myHandlerConstructor;
0210:
0211: /**
0212: * This service's log.
0213: */
0214: protected Log myLog;
0215:
0216: /**
0217: * Handlerpool.
0218: */
0219: transient protected HandlerPool myPool;
0220:
0221: /**
0222: * Number of instantiated handlers (ever).
0223: */
0224: protected int myHandlerCount;
0225:
0226: private int longRunnerDestroyCount;
0227:
0228: private String userId;
0229: private String groupId;
0230: private boolean libLoaded = false;
0231:
0232: /**
0233: * Default-Constructor. This constructor has to be called
0234: * in order to initialize data structures etc.
0235: */
0236: public Service() {
0237: myName = new String("Service"); // default name
0238: myLog = Log.getLog(null);
0239: myAlive = false;
0240: stopped = false;
0241: myPool = new HandlerPool();
0242: myFactory = Factory.getFactory();
0243: myListeners = new Hashtable();
0244: myPool = new HandlerPool();
0245: myAttributes = new Hashtable();
0246: mySoTimeout = 0;
0247: myMinorVersion = 0;
0248: myMajorVersion = 0;
0249: myHandlerCount = 0;
0250: longRunnerDestroyCount = 0;
0251: }
0252:
0253: /**
0254: * Gets threadgroup of this <code>Service</code>.
0255: *
0256: * @return threadgroup
0257: */
0258: public ThreadGroup getThreadGroup() {
0259: if (myThreadGroup != null) {
0260: return myThreadGroup;
0261: }
0262:
0263: synchronized (this ) {
0264: if (myThreadGroup != null) {
0265: return myThreadGroup;
0266: }
0267:
0268: myThreadGroup = new ThreadGroup(getName());
0269: }
0270:
0271: return myThreadGroup;
0272: }
0273:
0274: /**
0275: * Indicates whether this <code>Service</code> is alive or not.
0276: *
0277: * @return <code>true</code> or <code>false</code>
0278: */
0279: public synchronized boolean isAlive() {
0280: return myAlive;
0281: }
0282:
0283: /**
0284: * Indicates, whether the <code>stopped</code> Flag was set.
0285: *
0286: * @return <code>true</code> or <code>false</code>
0287: */
0288: public boolean isStopped() {
0289: return stopped;
0290: }
0291:
0292: /**
0293: * Starts this <code>Service</code>.
0294: *
0295: * @exception ServerException if it is not possible to
0296: * start this <code>Service</code>
0297: */
0298: public synchronized void start() throws ServerException {
0299: Enumeration e = myListeners.elements();
0300:
0301: while (e.hasMoreElements()) {
0302: I_Listener theListener = (I_Listener) e.nextElement();
0303:
0304: try {
0305: theListener.start();
0306: } catch (Throwable t) {
0307: // t.printStackTrace();
0308:
0309: if (t instanceof ServerException) {
0310: throw (ServerException) t;
0311: } else {
0312: throw new ServerException(
0313: "Failed to start listener '" + getName()
0314: + "'.", t);
0315: }
0316: }
0317: try {
0318: setUserAndGroup();
0319: } catch (Throwable t) {
0320: if (t instanceof ServerException) {
0321: throw (ServerException) t;
0322: } else {
0323: throw new ServerException(
0324: "Failed to set user and group for '"
0325: + getName() + "'.", t);
0326: }
0327: }
0328: }
0329:
0330: if (Log.getLog(getName()).isLog(C_Log.MODULE)) {
0331: Log.getLog(getName()).log(
0332: "Service '" + getName() + "' started.",
0333: C_Log.MODULE);
0334: }
0335:
0336: myAlive = true;
0337: myRunningSince = System.currentTimeMillis();
0338: }
0339:
0340: /**
0341: * Stops this <code>Service</code>.
0342: *
0343: * @exception ServerException if it is not possible to
0344: * stop this <code>Service</code>
0345: */
0346: public synchronized void stop() throws ServerException {
0347: if (Log.getLog(getName()).isLog(C_Log.METHOD)) {
0348: Log.getLog(getName()).log(
0349: "Trying to stop service '" + getName() + "'.",
0350: C_Log.METHOD);
0351: }
0352:
0353: Enumeration e = myListeners.elements();
0354:
0355: while (e.hasMoreElements()) {
0356: I_Listener theListener = (I_Listener) e.nextElement();
0357:
0358: try {
0359: theListener.stop();
0360: } catch (Throwable t) {
0361: if (t instanceof ServerException) {
0362: throw (ServerException) t;
0363: } else {
0364: throw new ServerException(
0365: "Failed to stop listener '"
0366: + theListener.getName() + "'.", t);
0367: }
0368: }
0369: }
0370:
0371: myPool.clear();
0372:
0373: try {
0374: getThreadGroup().interrupt(); // be gentle, at first,
0375: wait(2000); // give some time...,
0376: getThreadGroup().stop(); // then strike with all your might!!!
0377: } catch (Throwable t) {
0378: if (Log.getLog(getName()).isLog(C_Log.ERROR)) {
0379: Log.getLog(getName()).log(
0380: "Trouble while stopping threadgroup: "
0381: + t.toString(), C_Log.ERROR);
0382: Log.getLog(getName()).log(t, C_Log.ERROR);
0383: }
0384: }
0385:
0386: if (Log.getLog(getName()).isLog(C_Log.MODULE)) {
0387: Log.getLog(getName()).log(
0388: "Service '" + getName() + "' stopped.",
0389: C_Log.MODULE);
0390: }
0391:
0392: myAlive = false;
0393: myRunningSince = 0;
0394: }
0395:
0396: /**
0397: * Restarts this <code>Service</code>.
0398: *
0399: * @exception ServerException if it is not possible to
0400: * either start or stop this <code>Service</code>
0401: */
0402: public synchronized void restart() throws ServerException {
0403: stop();
0404: start();
0405: }
0406:
0407: /**
0408: * Indicates whether this server is restartable or not. This depends on the user it is run under
0409: * and the ports it is bound to.
0410: */
0411: public boolean isRestartable() {
0412: boolean restartable = true;
0413: for (Enumeration e = myListeners.elements(); e
0414: .hasMoreElements()
0415: && restartable;) {
0416: I_Listener listener = (I_Listener) e.nextElement();
0417: if (listener.getPort() < 1024)
0418: restartable = (userId == null && groupId == null);
0419: }
0420: return restartable;
0421: }
0422:
0423: /**
0424: * Sets the user and group id this server shall run under.
0425: */
0426: private synchronized void setUserAndGroup() throws ServerException {
0427: // this does not seem to work yet (rik)
0428: if (userId != null || groupId != null) {
0429: if (!libLoaded) {
0430: if (Log.isLog(C_Log.METHOD, getName())) {
0431: Log
0432: .getLog(getName())
0433: .log(
0434: "java.library.path: "
0435: + System
0436: .getProperty("java.library.path"),
0437: C_Log.METHOD);
0438: }
0439: System.loadLibrary("tagtraum");
0440: libLoaded = true;
0441: }
0442: if (!setUserAndGroup(userId, groupId))
0443: throw new ServerException("Failed to set user "
0444: + userId + " and group " + groupId + ".");
0445: }
0446: }
0447:
0448: private native boolean setUserAndGroup(String userId, String groupId);
0449:
0450: /**
0451: * Is called when a <code>SO_TIMEOUT</code> happened in one of the
0452: * {@link I_Listener}s. Default behavior is trim the {@link HandlerPool}
0453: * to a minimum.
0454: *
0455: * @see #setMinHandlerThreads();
0456: */
0457: public void handleSoTimeout() {
0458: if (Log.isLog(C_Log.METHOD, getName())) {
0459: Log.getLog(getName())
0460: .log("SoTimeout: Service.handleSoTimeout.",
0461: C_Log.METHOD);
0462: }
0463:
0464: int oldsize = myPool.size();
0465:
0466: // also cut the pool, if half of cached handlers are pooled
0467: int trimToSize = (myPool.countRegisteredHandlers() - minHandlers)
0468: / 2 + minHandlers;
0469:
0470: if (oldsize > trimToSize && oldsize > minHandlers) {
0471: if (Log.isLog(C_Log.METHOD, getName())) {
0472: Log.getLog(getName()).log(
0473: "SoTimeout: Trying to trim pool from "
0474: + oldsize + " to " + trimToSize + ".",
0475: C_Log.METHOD);
0476: }
0477:
0478: myPool.trim(trimToSize);
0479: System.gc();
0480:
0481: if (Log.isLog(C_Log.METHOD, getName())) {
0482: Log.getLog(getName()).log(
0483: "SoTimeout: Trimmed pool from " + oldsize
0484: + " to " + trimToSize + ".",
0485: C_Log.METHOD);
0486: }
0487: }
0488: }
0489:
0490: /**
0491: * Sets <code>SO_TIMEOUT</code> for the accepting sockets.
0492: *
0493: * @param aSoTimeout time in ms
0494: */
0495: public void setSoTimeout(int aSoTimeout) {
0496: if (aSoTimeout < 0) {
0497: throw new IllegalArgumentException(
0498: "SO_TIMEOUT can't be less than zero.");
0499: }
0500:
0501: mySoTimeout = aSoTimeout;
0502: }
0503:
0504: /**
0505: * Returns <code>SO_TIMEOUT</code> for the accepting sockets.
0506: *
0507: * @param aSoTimeout time in ms
0508: */
0509: public int getSoTimeout() {
0510: return mySoTimeout;
0511: }
0512:
0513: /**
0514: * Returns a server info String.
0515: *
0516: * @return a server info string
0517: */
0518: public String getServerInfo() {
0519: UnSyncStringBuffer sb = new UnSyncStringBuffer(myName);
0520:
0521: sb.append('/');
0522: sb.append(myMajorVersion);
0523: sb.append('.');
0524: sb.append(myMinorVersion);
0525:
0526: return sb.toString();
0527: }
0528:
0529: /**
0530: * Sets the factory used for instatiating the handlers.
0531: *
0532: * @param aFactory the factory
0533: */
0534: public void setHandlerFactory(Factory aFactory) {
0535: myFactory = aFactory;
0536: }
0537:
0538: /**
0539: * Returns the factory used for instatiating the handlers.
0540: *
0541: * @return the factory
0542: */
0543: public Factory getHandlerFactory() {
0544: return myFactory;
0545: }
0546:
0547: /**
0548: * Sets the name of the handler class to use. The class
0549: * has to implement the interface {@link I_Handler}.
0550: *
0551: * @param aClassname the handler classname
0552: * @see I_Handler
0553: */
0554: public void setHandlerClassname(String aClassname) {
0555: myHandlerClassname = aClassname;
0556: }
0557:
0558: /**
0559: * Method declaration
0560: *
0561: *
0562: * @return
0563: *
0564: * @throws Exception
0565: *
0566: * @see
0567: */
0568: protected Constructor getHandlerConstructor() throws Exception {
0569: if (myHandlerConstructor != null) {
0570: return myHandlerConstructor;
0571: }
0572:
0573: synchronized (this ) {
0574: if (myHandlerConstructor != null) {
0575: return myHandlerConstructor;
0576: }
0577:
0578: myHandlerConstructor = Class.forName(
0579: myFactory.resolveAlias(myHandlerClassname))
0580: .getConstructor(new Class[] { ThreadGroup.class });
0581: }
0582:
0583: return myHandlerConstructor;
0584: }
0585:
0586: /**
0587: * Method declaration
0588: *
0589: *
0590: * @return
0591: *
0592: * @see
0593: */
0594: protected Object[] getHandlerConstructorArgs() {
0595: if (myHandlerConstructorArgs != null) {
0596: return myHandlerConstructorArgs;
0597: }
0598:
0599: synchronized (this ) {
0600: if (myHandlerConstructorArgs != null) {
0601: return myHandlerConstructorArgs;
0602: }
0603:
0604: myHandlerConstructorArgs = new Object[] { getThreadGroup() };
0605: }
0606:
0607: return myHandlerConstructorArgs;
0608: }
0609:
0610: /**
0611: * Return the name of the handler's class.
0612: *
0613: * @return the handler's classname
0614: */
0615: public String getHandlerClassname() {
0616: return myHandlerClassname;
0617: }
0618:
0619: /**
0620: * Returns an attribute.
0621: *
0622: * @return the attribute or <code>null</code>, if it doesn't exist.
0623: * @param key the attribute's key
0624: */
0625: public Object getAttribute(String key) {
0626: return myAttributes.get(key);
0627: }
0628:
0629: /**
0630: * Sets an attribute.
0631: *
0632: * @param key key of this attribute
0633: * @param value value of this attribute
0634: */
0635: public void setAttribute(String key, Object value) {
0636: myAttributes.put(key, value);
0637: }
0638:
0639: /**
0640: * Enumeration of all attribute keys.
0641: *
0642: * @return an Enumeration of all attribute keys
0643: */
0644: public Enumeration getAttributeNames() {
0645: return myAttributes.keys();
0646: }
0647:
0648: /**
0649: * Returns the name of this <code>Service</code>.
0650: *
0651: * @return the name of this <code>Service</code>
0652: */
0653: public String getName() {
0654: return myName;
0655: }
0656:
0657: /**
0658: * Sets the name of this <code>Service</code>.
0659: *
0660: * @param name name of this <code>Service</code>
0661: */
0662: public void setName(String name) {
0663: if (name == null) {
0664: throw new NullPointerException(
0665: "Name of service can't be null.");
0666: }
0667:
0668: myName = name;
0669: myLog = Log.getLog(myName);
0670: }
0671:
0672: /**
0673: * Unregisteres a Handler from this service.
0674: */
0675: public void removeHandler(I_Handler aHandler) {
0676: if (myLog.isLog(Log.METHOD)) {
0677: myLog.log("Service#removeHandler(): " + aHandler.toString()
0678: + " (try)", Log.METHOD);
0679: }
0680:
0681: myPool.unregisterHandler(aHandler);
0682:
0683: if (myLog.isLog(Log.METHOD)) {
0684: myLog.log("Service#removeHandler(): " + aHandler.toString()
0685: + " (done)", Log.METHOD);
0686: }
0687: }
0688:
0689: /**
0690: * Returns a ready-to-use {@link I_Handler}.
0691: *
0692: * @return a {@link I_Handler}
0693: * @exception HandlerException if it is not possible to get a {@link I_Handler}
0694: */
0695: public I_Handler getHandler() throws HandlerException {
0696: // try to get a Handler from the pool
0697: I_Handler aHandler = (I_Handler) myPool.get();
0698:
0699: // if we got a handler from the pool, return it
0700: if (aHandler != null) {
0701: return aHandler;
0702: }
0703:
0704: // we didn't get a Handler, so we're checking, whether we are allowed
0705: // to instantiate a new one.
0706: // for liveliness this is not synchronized with the pool - so we might
0707: // end up with more Handlers than specified in maxHandlers
0708: if (myPool.countRegisteredHandlers() <= maxHandlers) {
0709: aHandler = newHandler();
0710: } else {
0711: // we are not allowed to instantiate a new Handler, so we have to
0712: // wait for one being recycled.
0713: if (myLog.isLog(C_Log.METHOD)) {
0714: myLog.log("Reached maximum number of handlers ("
0715: + getMaxHandlerThreads()
0716: + "). Waiting for a handler being recycled.",
0717: C_Log.METHOD);
0718: }
0719:
0720: // keeps track of how long we waited to obtain a Handler
0721: int count = 0;
0722:
0723: try {
0724: // wait at most a second to obtain a Handler...
0725: while ((aHandler = (I_Handler) myPool.get(1000)) == null) {
0726: // ...then increase count
0727: count++;
0728:
0729: // if we waited 10 seconds, give up
0730: if (count == 10) {
0731: throw new HandlerException(
0732: "Couldn't obtain Handler after 10 seconds. Giving up.");
0733: }
0734: }
0735: } catch (InterruptedException ie) {
0736: throw new HandlerException(
0737: "Interruption while waiting for free Handler: "
0738: + ie.toString());
0739: }
0740: // we now have a recycled Handler
0741: }
0742:
0743: return aHandler;
0744: }
0745:
0746: /**
0747: * Returns a new {@link I_Handler} instance.
0748: *
0749: *
0750: * @return a handler
0751: *
0752: * @throws HandlerException if something goes wrong
0753: */
0754: protected I_Handler newHandler() throws HandlerException {
0755: I_Handler aHandler = null;
0756:
0757: try {
0758: // get new instance
0759: aHandler = (I_Handler) getHandlerConstructor().newInstance(
0760: getHandlerConstructorArgs());
0761:
0762: aHandler.setName("HandlerThread-" + myHandlerCount);
0763: // and initialize
0764: aHandler.init(this );
0765:
0766: // increase handlercount - this is for naming only
0767: myHandlerCount++;
0768:
0769: // register the Handler with the pool, note that the Handler
0770: // is not added to the pool here.
0771: myPool.registerHandler(aHandler);
0772:
0773: if (myLog.isLog(C_Log.METHOD)) {
0774: myLog
0775: .log("Service#newHandler(): "
0776: + aHandler.getName() + ". Count: "
0777: + getHandlerCount(), C_Log.METHOD);
0778: }
0779: } catch (HandlerException he) {
0780: throw he;
0781: } catch (Exception e) {
0782: // instantiation exceptions and so on...
0783: throw new HandlerException(e);
0784: }
0785:
0786: // we have a newly instantiated and initialized Handler,
0787: // so let's give it back
0788: return aHandler;
0789: }
0790:
0791: /**
0792: * Recycles a {@link I_Handler}.
0793: *
0794: * @param aHandler {@link I_Handler} to recycle
0795: */
0796: public void recycleHandler(I_Handler aHandler) {
0797: if (myLog.isLog(Log.METHOD)) {
0798: myLog.log(
0799: "Service#recycleHandler(): " + aHandler.getName(),
0800: Log.METHOD);
0801: }
0802:
0803: myPool.add(aHandler);
0804: // sanity check for long running Handlers
0805: destroyLongRunningHandlers();
0806: }
0807:
0808: /**
0809: * Method.
0810: *
0811: *
0812: * @see
0813: */
0814: protected void destroyLongRunningHandlers() {
0815: // do the real ckeck only every thousendth time
0816: if (longRunnerDestroyCount < 1000) {
0817: longRunnerDestroyCount++;
0818:
0819: return;
0820: }
0821:
0822: synchronized (this ) {
0823: // so it can't be stopped while we're in here.
0824: longRunnerDestroyCount = 0;
0825:
0826: long now = System.currentTimeMillis();
0827: ThreadGroup tg = getThreadGroup();
0828:
0829: Thread[] t = new Thread[tg.activeCount()];
0830: int count = getThreadGroup().enumerate(t);
0831:
0832: if (myLog.isLog(Log.METHOD)) {
0833: myLog.log("ThreadGroup#list():", Log.METHOD);
0834: }
0835:
0836: for (int i = 0; i < count; i++) {
0837: if (myLog.isLog(Log.METHOD)) {
0838: myLog.log(t[i], Log.METHOD);
0839: }
0840:
0841: if (t[i] != null && t[i] instanceof I_Handler) {
0842: I_Handler handler = (I_Handler) t[i];
0843:
0844: if (handler.getServiceStart() != -1) {
0845: // if a thread is longer than 5 min in service(), destroy it.
0846: long time = now - handler.getServiceStart();
0847:
0848: if (time > 1000L * 60L * 5L) {
0849: if (myLog.isLog(Log.ERROR)) {
0850: myLog.log(
0851: "Service#destroyLongRunningHandlers(): "
0852: + handler.toString()
0853: + " (" + time + "ms)",
0854: Log.ERROR);
0855: }
0856:
0857: removeHandler(handler);
0858: }
0859: }
0860:
0861: }
0862: }
0863: }
0864: }
0865:
0866: /**
0867: * Sets the max number of {@link Handler}s.
0868: *
0869: * @param max max number of {@link Handler}s
0870: */
0871: public void setMaxHandlerThreads(int max) {
0872: if (max < 1) {
0873: throw new IllegalArgumentException(
0874: "maxHandlers must be greater than zero.");
0875: }
0876:
0877: if (max < getMinHandlerThreads()) {
0878: throw new IllegalArgumentException(
0879: "maxHandlers must be greater than minHandlers.");
0880: }
0881:
0882: maxHandlers = max;
0883:
0884: myPool.setCapacity(maxHandlers);
0885: }
0886:
0887: /**
0888: * Returns the max number of {@link Handler}s.
0889: *
0890: * @return max number of {@link Handler}s
0891: */
0892: public int getMaxHandlerThreads() {
0893: return maxHandlers;
0894: }
0895:
0896: /**
0897: * Sets the min number of {@link Handler}s.
0898: *
0899: * @param min min number of {@link Handler}s
0900: */
0901: public void setMinHandlerThreads(int min) {
0902: if (min < 0) {
0903: throw new IllegalArgumentException(
0904: "minHandlers must be zero or greater.");
0905: }
0906:
0907: if (min > getMaxHandlerThreads()) {
0908: throw new IllegalArgumentException(
0909: "maxHandlers must be greater than minHandlers.");
0910: }
0911:
0912: minHandlers = min;
0913: }
0914:
0915: /**
0916: * Returns the min number of {@link Handler}s.
0917: *
0918: * @return min number of {@link Handler}s
0919: */
0920: public int getMinHandlerThreads() {
0921: return minHandlers;
0922: }
0923:
0924: /**
0925: * Adds a Listener.
0926: *
0927: * @param aListener a listener
0928: */
0929: public synchronized void addListener(I_Listener aListener) {
0930: myListeners.put(aListener.getName(), aListener);
0931: aListener.setService(this );
0932: }
0933:
0934: /**
0935: * Removes a Listener.
0936: *
0937: * @param aName a listener name
0938: */
0939: public synchronized void removeListener(String aName) {
0940: myListeners.remove(aName);
0941: }
0942:
0943: /**
0944: * Removes all listeners.
0945: */
0946: public synchronized void removeAllListeners() {
0947: myListeners.clear();
0948: }
0949:
0950: /**
0951: * Returns a listener.
0952: *
0953: * @param aName a listener name
0954: * @return a listener or <code>null</code>
0955: */
0956: public synchronized I_Listener getListener(String aName) {
0957: return (I_Listener) myListeners.get(aName);
0958: }
0959:
0960: /**
0961: * Returns an Enumeration of all listener names.
0962: *
0963: * @return the listener names
0964: */
0965: public Enumeration listenerNames() {
0966: return myListeners.keys();
0967: }
0968:
0969: /**
0970: * Returns a <code>2</code> for a service version 2.4.
0971: *
0972: * @return major version
0973: */
0974: public int getMajorVersion() {
0975: return myMajorVersion;
0976: }
0977:
0978: /**
0979: * Returns a <code>4</code> for a service version 2.4.
0980: *
0981: * @return minor version
0982: */
0983: public int getMinorVersion() {
0984: return myMinorVersion;
0985: }
0986:
0987: /**
0988: * Sets the major version for this service.
0989: *
0990: * @param aVersion major version
0991: */
0992: public void setMajorVersion(int aVersion) {
0993: myMajorVersion = aVersion;
0994: }
0995:
0996: /**
0997: * Sets the minor version for this service.
0998: *
0999: * @param aVersion minor version
1000: */
1001: public void setMinorVersion(int aVersion) {
1002: myMinorVersion = aVersion;
1003: }
1004:
1005: /**
1006: * Returns the number of currently active handlers.
1007: *
1008: * @return the number of currently active handlers
1009: */
1010: public int getActiveHandlerCount() {
1011: return myPool.countRegisteredHandlers() - myPool.size();
1012: }
1013:
1014: /**
1015: * Returns the number of registered handlers.
1016: *
1017: * @return the number of registered handlers
1018: */
1019: public int getHandlerCount() {
1020: return myPool.countRegisteredHandlers();
1021: }
1022:
1023: /**
1024: * Returns the highest number of active handlers that have been used in the past.
1025: *
1026: * @return the number of currently active handlers
1027: */
1028: public int getPeakActiveHandlerCount() {
1029: return myPool.countPeakRegisteredHandlers();
1030: }
1031:
1032: /**
1033: * Returns the time when the service was started
1034: *
1035: * @return the time when the service was started
1036: */
1037: public long runningSince() {
1038: return myRunningSince;
1039: }
1040:
1041: public String getGroupId() {
1042: return groupId;
1043: }
1044:
1045: public void setGroupId(String groupId) {
1046: this .groupId = groupId;
1047: }
1048:
1049: public String getUserId() {
1050: return userId;
1051: }
1052:
1053: public void setUserId(String userId) {
1054: this.userId = userId;
1055: }
1056:
1057: }
|