0001: /*
0002: * $Id: API.java,v 1.369 2007/09/18 08:45:06 agoubard Exp $
0003: *
0004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
0005: * See the COPYRIGHT file for redistribution and use restrictions.
0006: */
0007: package org.xins.server;
0008:
0009: import java.io.InputStream;
0010: import java.io.PrintWriter;
0011: import java.io.StringWriter;
0012: import java.util.ArrayList;
0013: import java.util.Enumeration;
0014: import java.util.HashMap;
0015: import java.util.Iterator;
0016: import java.util.List;
0017: import java.util.Map;
0018: import java.util.Properties;
0019: import java.util.TimeZone;
0020:
0021: import org.xins.common.FormattedParameters;
0022: import org.xins.common.MandatoryArgumentChecker;
0023: import org.xins.common.Utils;
0024: import org.xins.common.collections.BasicPropertyReader;
0025: import org.xins.common.collections.InvalidPropertyValueException;
0026: import org.xins.common.collections.MissingRequiredPropertyException;
0027: import org.xins.common.collections.PropertyReader;
0028: import org.xins.common.manageable.BootstrapException;
0029: import org.xins.common.manageable.DeinitializationException;
0030: import org.xins.common.manageable.InitializationException;
0031: import org.xins.common.manageable.Manageable;
0032: import org.xins.common.net.IPAddressUtils;
0033: import org.xins.common.spec.APISpec;
0034: import org.xins.common.spec.InvalidSpecificationException;
0035: import org.xins.common.text.DateConverter;
0036: import org.xins.common.text.ParseException;
0037: import org.xins.common.xml.Element;
0038: import org.xins.common.xml.ElementBuilder;
0039:
0040: /**
0041: * Base class for API implementation classes.
0042: *
0043: * @version $Revision: 1.369 $ $Date: 2007/09/18 08:45:06 $
0044: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
0045: * @author <a href="mailto:anthony.goubard@japplis.com">Anthony Goubard</a>
0046: * @author <a href="mailto:tauseef.rehman@orange-ftgroup.com">Tauseef Rehman</a>
0047: *
0048: * @since XINS 1.0.0
0049: */
0050: public abstract class API extends Manageable {
0051:
0052: /**
0053: * Successful empty call result.
0054: */
0055: static final FunctionResult SUCCESSFUL_RESULT = new FunctionResult();
0056:
0057: /**
0058: * The runtime (initialization) property that defines the ACL (access
0059: * control list) rules.
0060: */
0061: private static final String ACL_PROPERTY = "org.xins.server.acl";
0062:
0063: /**
0064: * The name of the bootstrap property that specifies the version of the API.
0065: */
0066: static final String API_VERSION_PROPERTY = "org.xins.api.version";
0067:
0068: /**
0069: * The name of the bootstrap property that specifies the hostname of the
0070: * machine the package was built on.
0071: */
0072: private static final String BUILD_HOST_PROPERTY = "org.xins.api.build.host";
0073:
0074: /**
0075: * The name of the bootstrap property that specifies the time the package was
0076: * built.
0077: */
0078: private static final String BUILD_TIME_PROPERTY = "org.xins.api.build.time";
0079:
0080: /**
0081: * The name of the bootstrap property that specifies which version of XINS was
0082: * used to build the package.
0083: */
0084: private static final String BUILD_XINS_VERSION_PROPERTY = "org.xins.api.build.version";
0085:
0086: /**
0087: * The engine that owns this <code>API</code> object.
0088: */
0089: private Engine _engine;
0090:
0091: /**
0092: * The name of this API. Cannot be <code>null</code> and cannot be an empty
0093: * string.
0094: */
0095: private final String _name;
0096:
0097: /**
0098: * List of registered manageable objects. See {@link #add(Manageable)}.
0099: *
0100: * <p />This field is initialized to a non-<code>null</code> value by the
0101: * constructor.
0102: */
0103: private final List _manageableObjects;
0104:
0105: /**
0106: * Map that maps function names to <code>Function</code> instances.
0107: * Contains all functions associated with this API.
0108: *
0109: * <p />This field is initialized to a non-<code>null</code> value by the
0110: * constructor.
0111: */
0112: private final Map _functionsByName;
0113:
0114: /**
0115: * List of all functions. This field cannot be <code>null</code>.
0116: */
0117: private final List _functionList;
0118:
0119: /**
0120: * The build-time settings. This field is initialized exactly once by
0121: * {@link #bootstrap(PropertyReader)}. It can be <code>null</code> before
0122: * that.
0123: */
0124: private PropertyReader _buildSettings;
0125:
0126: /**
0127: * The {@link RuntimeProperties} containing the method to verify and access
0128: * the defined runtime properties.
0129: */
0130: private RuntimeProperties _emptyProperties;
0131:
0132: /**
0133: * The runtime-time settings. This field is initialized by
0134: * {@link #init(PropertyReader)}. It can be <code>null</code> before that.
0135: */
0136: private PropertyReader _runtimeSettings;
0137:
0138: /**
0139: * Timestamp indicating when this API instance was created.
0140: */
0141: private final long _startupTimestamp;
0142:
0143: /**
0144: * Last time the statistics were reset. Initially the startup timestamp.
0145: */
0146: private long _lastStatisticsReset;
0147:
0148: /**
0149: * Host name for the machine that was used for this build.
0150: */
0151: private String _buildHost;
0152:
0153: /**
0154: * Time stamp that indicates when this build was done.
0155: */
0156: private String _buildTime;
0157:
0158: /**
0159: * XINS version used to build the web application package.
0160: */
0161: private String _buildVersion;
0162:
0163: /**
0164: * The time zone used when generating dates for output.
0165: */
0166: private final TimeZone _timeZone;
0167:
0168: /**
0169: * Version of the API.
0170: */
0171: private String _apiVersion;
0172:
0173: /**
0174: * The API specific access rule list.
0175: */
0176: private AccessRuleList _apiAccessRuleList;
0177:
0178: /**
0179: * The general access rule list.
0180: */
0181: private AccessRuleList _accessRuleList;
0182:
0183: /**
0184: * The API specification.
0185: */
0186: private APISpec _apiSpecification;
0187:
0188: /**
0189: * The local IP address.
0190: */
0191: private String _localIPAddress;
0192:
0193: /**
0194: * Mapping from function name to the call ID for all meta-functions. This
0195: * field is never <code>null</code>.
0196: */
0197: private final HashMap _metaFunctionCallIDs;
0198:
0199: /**
0200: * Flag indicating that the API is down for maintenance.
0201: */
0202: private boolean _apiDisabled;
0203:
0204: /**
0205: * Constructs a new <code>API</code> object.
0206: *
0207: * @param name
0208: * the name of the API, cannot be <code>null</code> nor can it be an
0209: * empty string.
0210: *
0211: * @throws IllegalArgumentException
0212: * if <code>name == null
0213: * || name.{@link String#length() length()} < 1</code>.
0214: */
0215: protected API(String name) throws IllegalArgumentException {
0216:
0217: // Check preconditions
0218: MandatoryArgumentChecker.check("name", name);
0219: if (name.length() < 1) {
0220: String message = "name.length() == " + name.length();
0221: throw new IllegalArgumentException(message);
0222: }
0223:
0224: // Initialize fields
0225: _name = name;
0226: _startupTimestamp = System.currentTimeMillis();
0227: _lastStatisticsReset = _startupTimestamp;
0228: _manageableObjects = new ArrayList(20);
0229: _functionsByName = new HashMap(89);
0230: _functionList = new ArrayList(80);
0231: _emptyProperties = new RuntimeProperties();
0232: _timeZone = TimeZone.getDefault();
0233: _localIPAddress = IPAddressUtils.getLocalHostIPAddress();
0234: _apiDisabled = false;
0235:
0236: // Initialize mapping from meta-function to call ID
0237: _metaFunctionCallIDs = new HashMap(89);
0238: _metaFunctionCallIDs.put("_NoOp", new Counter());
0239: _metaFunctionCallIDs.put("_GetFunctionList", new Counter());
0240: _metaFunctionCallIDs.put("_GetStatistics", new Counter());
0241: _metaFunctionCallIDs.put("_GetVersion", new Counter());
0242: _metaFunctionCallIDs.put("_CheckLinks", new Counter());
0243: _metaFunctionCallIDs.put("_GetSettings", new Counter());
0244: _metaFunctionCallIDs.put("_DisableFunction", new Counter());
0245: _metaFunctionCallIDs.put("_EnableFunction", new Counter());
0246: _metaFunctionCallIDs.put("_ResetStatistics", new Counter());
0247: _metaFunctionCallIDs.put("_ReloadProperties", new Counter());
0248: _metaFunctionCallIDs.put("_WSDL", new Counter());
0249: _metaFunctionCallIDs.put("_SMD", new Counter());
0250: _metaFunctionCallIDs.put("_DisableAPI", new Counter());
0251: _metaFunctionCallIDs.put("_EnableAPI", new Counter());
0252: }
0253:
0254: /**
0255: * Gets the name of this API.
0256: *
0257: * @return
0258: * the name of this API, never <code>null</code> and never an empty
0259: * string.
0260: */
0261: public final String getName() {
0262: return _name;
0263: }
0264:
0265: /**
0266: * Gets the list of the functions of this API.
0267: *
0268: * @return
0269: * the functions of this API as a {@link List} of {@link Function} objects, never <code>null</code>.
0270: *
0271: * @since XINS 1.5.0.
0272: */
0273: public final List getFunctionList() {
0274: return _functionList;
0275: }
0276:
0277: /**
0278: * Gets the bootstrap properties specified for the API.
0279: *
0280: * @return
0281: * the bootstrap properties, cannot be <code>null</code>.
0282: *
0283: * @since XINS 1.5.0.
0284: */
0285: public PropertyReader getBootstrapProperties() {
0286: return _buildSettings;
0287: }
0288:
0289: /**
0290: * Gets the API runtime properties.
0291: *
0292: * @return
0293: * the runtime properties, cannot be <code>null</code>.
0294: */
0295: PropertyReader getRuntimeProperties() {
0296: return _runtimeSettings;
0297: }
0298:
0299: /**
0300: * Gets the runtime properties specified in the implementation.
0301: *
0302: * @return
0303: * the runtime properties for the API, cannot be <code>null</code>.
0304: */
0305: public RuntimeProperties getProperties() {
0306:
0307: // This method is overridden by the APIImpl to return the generated
0308: // RuntimeProperties class which contains the runtime properties.
0309: return _emptyProperties;
0310: }
0311:
0312: /**
0313: * Gets the timestamp that indicates when this <code>API</code> instance
0314: * was created.
0315: *
0316: * @return
0317: * the time this instance was constructed, as a number of milliseconds
0318: * since the
0319: * <a href="http://en.wikipedia.org/wiki/Unix_Epoch">UNIX Epoch</a>.
0320: */
0321: public final long getStartupTimestamp() {
0322: return _startupTimestamp;
0323: }
0324:
0325: /**
0326: * Returns the applicable time zone.
0327: *
0328: * @return
0329: * the time zone, never <code>null</code>.
0330: */
0331: public final TimeZone getTimeZone() {
0332: return _timeZone;
0333: }
0334:
0335: /**
0336: * Gets the resource in the WAR file.
0337: *
0338: * @param path
0339: * the path for the resource, cannot be <code>null</code> and should start with /.
0340: *
0341: * @return
0342: * the InputStream to use to read this resource or <code>null</code> if
0343: * the resource cannot be found.
0344: *
0345: * @throws IllegalArgumentException
0346: * if <code>path == null</code> or if the path doesn't start with /.
0347: *
0348: * @since XINS 2.0.
0349: */
0350: public final InputStream getResourceAsStream(String path)
0351: throws IllegalArgumentException {
0352: return _engine.getResourceAsStream(path);
0353: }
0354:
0355: /**
0356: * Bootstraps this API (wrapper method). This method calls
0357: * {@link #bootstrapImpl2(PropertyReader)}.
0358: *
0359: * @param buildSettings
0360: * the build-time configuration properties, not <code>null</code>.
0361: *
0362: * @throws IllegalStateException
0363: * if this API is currently not bootstraping.
0364: *
0365: * @throws MissingRequiredPropertyException
0366: * if a required property is not given.
0367: *
0368: * @throws InvalidPropertyValueException
0369: * if a property has an invalid value.
0370: *
0371: * @throws BootstrapException
0372: * if the bootstrap fails.
0373: */
0374: protected final void bootstrapImpl(PropertyReader buildSettings)
0375: throws IllegalStateException,
0376: MissingRequiredPropertyException,
0377: InvalidPropertyValueException, BootstrapException {
0378:
0379: // Check state
0380: Manageable.State state = getState();
0381: if (state != BOOTSTRAPPING) {
0382: String message = "State is " + state + " instead of "
0383: + BOOTSTRAPPING + '.';
0384: Utils.logProgrammingError(message);
0385: throw new IllegalStateException(message);
0386: }
0387:
0388: // Log the time zone
0389: String tzShortName = _timeZone.getDisplayName(false,
0390: TimeZone.SHORT);
0391: String tzLongName = _timeZone.getDisplayName(false,
0392: TimeZone.LONG);
0393: Log.log_3404(tzShortName, tzLongName);
0394:
0395: // Store the build-time settings
0396: _buildSettings = buildSettings;
0397:
0398: // Get build-time properties
0399: _apiVersion = _buildSettings.get(API_VERSION_PROPERTY);
0400: _buildHost = _buildSettings.get(BUILD_HOST_PROPERTY);
0401: _buildTime = _buildSettings.get(BUILD_TIME_PROPERTY);
0402: _buildVersion = _buildSettings.get(BUILD_XINS_VERSION_PROPERTY);
0403:
0404: Log.log_3212(_buildHost, _buildTime, _buildVersion, _name,
0405: _apiVersion);
0406:
0407: // Skip check if build version is not set
0408: if (_buildVersion == null) {
0409: // fall through
0410:
0411: // Check if build version identifies a production release of XINS
0412: } else if (!Library.isProductionRelease(_buildVersion)) {
0413: Log.log_3228(_buildVersion);
0414: }
0415:
0416: // Let the subclass perform initialization
0417: // TODO: What if bootstrapImpl2 throws an unexpected exception?
0418: bootstrapImpl2(buildSettings);
0419:
0420: // Bootstrap all instances
0421: int count = _manageableObjects.size();
0422: for (int i = 0; i < count; i++) {
0423: Manageable m = (Manageable) _manageableObjects.get(i);
0424: String className = m.getClass().getName();
0425: Log.log_3213(_name, className);
0426: try {
0427: m.bootstrap(_buildSettings);
0428:
0429: // Missing property
0430: } catch (MissingRequiredPropertyException exception) {
0431: Log.log_3215(_name, className, exception
0432: .getPropertyName(), exception.getDetail());
0433: throw exception;
0434:
0435: // Invalid property
0436: } catch (InvalidPropertyValueException exception) {
0437: Log.log_3216(_name, className, exception
0438: .getPropertyName(), exception
0439: .getPropertyValue(), exception.getReason());
0440: throw exception;
0441:
0442: // Catch BootstrapException and any other exceptions not caught
0443: // by previous catch statements
0444: } catch (Throwable exception) {
0445:
0446: // Log event
0447: Log.log_3217(exception, _name, className);
0448:
0449: // Throw a BootstrapException. If necessary, wrap around the
0450: // caught exception
0451: if (exception instanceof BootstrapException) {
0452: throw (BootstrapException) exception;
0453: } else {
0454: throw new BootstrapException(exception);
0455: }
0456: }
0457: }
0458:
0459: // Bootstrap all functions
0460: count = _functionList.size();
0461: for (int i = 0; i < count; i++) {
0462: Function f = (Function) _functionList.get(i);
0463: String functionName = f.getName();
0464: Log.log_3220(_name, functionName);
0465: try {
0466: f.bootstrap(_buildSettings);
0467:
0468: // Missing required property
0469: } catch (MissingRequiredPropertyException exception) {
0470: Log.log_3222(_name, functionName, exception
0471: .getPropertyName(), exception.getDetail());
0472: throw exception;
0473:
0474: // Invalid property value
0475: } catch (InvalidPropertyValueException exception) {
0476: Log.log_3223(_name, functionName, exception
0477: .getPropertyName(), exception
0478: .getPropertyValue(), exception.getReason());
0479: throw exception;
0480:
0481: // Catch BootstrapException and any other exceptions not caught
0482: // by previous catch statements
0483: } catch (Throwable exception) {
0484:
0485: // Log this event
0486: Log.log_3224(exception, _name, functionName);
0487:
0488: // Throw a BootstrapException. If necessary, wrap around the
0489: // caught exception
0490: if (exception instanceof BootstrapException) {
0491: throw (BootstrapException) exception;
0492: } else {
0493: throw new BootstrapException(exception);
0494: }
0495: }
0496: }
0497: }
0498:
0499: /**
0500: * Bootstraps this API (implementation method).
0501: *
0502: * <p />The implementation of this method in class {@link API} is empty.
0503: * Custom subclasses can perform any necessary bootstrapping in this
0504: * class.
0505: *
0506: * <p />Note that bootstrapping and initialization are different. Bootstrap
0507: * includes only the one-time configuration of the API based on the
0508: * build-time settings, while the initialization
0509: *
0510: * <p />The {@link #add(Manageable)} may be called from this method,
0511: * and from this method <em>only</em>.
0512: *
0513: * @param buildSettings
0514: * the build-time properties, guaranteed not to be <code>null</code>.
0515: *
0516: * @throws MissingRequiredPropertyException
0517: * if a required property is not given.
0518: *
0519: * @throws InvalidPropertyValueException
0520: * if a property has an invalid value.
0521: *
0522: * @throws BootstrapException
0523: * if the bootstrap fails.
0524: */
0525: protected void bootstrapImpl2(PropertyReader buildSettings)
0526: throws MissingRequiredPropertyException,
0527: InvalidPropertyValueException, BootstrapException {
0528: // empty
0529: }
0530:
0531: /**
0532: * Stores a reference to the <code>Engine</code> that owns this
0533: * <code>API</code> object.
0534: *
0535: * @param engine
0536: * the {@link Engine} instance, should not be <code>null</code>.
0537: */
0538: void setEngine(Engine engine) {
0539: _engine = engine;
0540: }
0541:
0542: /**
0543: * Triggers re-initialization of this API. This method is meant to be
0544: * called by API function implementations when it is anticipated that the
0545: * API should be re-initialized.
0546: */
0547: protected final void reinitializeImpl() {
0548: _engine.initAPI();
0549: }
0550:
0551: /**
0552: * Initializes this API.
0553: *
0554: * @param runtimeSettings
0555: * the runtime configuration settings, cannot be <code>null</code>.
0556: *
0557: * @throws MissingRequiredPropertyException
0558: * if a required property is missing.
0559: *
0560: * @throws InvalidPropertyValueException
0561: * if a property has an invalid value.
0562: *
0563: * @throws InitializationException
0564: * if the initialization failed for some other reason.
0565: *
0566: * @throws IllegalStateException
0567: * if this API is currently not initializing.
0568: */
0569: protected final void initImpl(PropertyReader runtimeSettings)
0570: throws MissingRequiredPropertyException,
0571: InvalidPropertyValueException, InitializationException,
0572: IllegalStateException {
0573:
0574: Log.log_3405(_name);
0575:
0576: // Store runtime settings
0577: _runtimeSettings = runtimeSettings;
0578:
0579: String propName = ConfigManager.CONFIG_RELOAD_INTERVAL_PROPERTY;
0580: String propValue = runtimeSettings.get(propName);
0581: int interval = ConfigManager.DEFAULT_CONFIG_RELOAD_INTERVAL;
0582: if (propValue != null && propValue.trim().length() > 0) {
0583: try {
0584: interval = Integer.parseInt(propValue);
0585: } catch (NumberFormatException e) {
0586: String detail = "Invalid interval. Must be a non-negative integer"
0587: + " number (32-bit signed).";
0588: throw new InvalidPropertyValueException(propName,
0589: propValue, detail);
0590: }
0591:
0592: if (interval < 0) {
0593: throw new InvalidPropertyValueException(propName,
0594: propValue,
0595: "Negative interval not allowed. Use 0 to disable reloading.");
0596: }
0597: }
0598:
0599: // Initialize ACL subsystem
0600:
0601: // First with the API specific access rule list
0602: if (_apiAccessRuleList != null) {
0603: _apiAccessRuleList.dispose();
0604: }
0605: _apiAccessRuleList = createAccessRuleList(runtimeSettings,
0606: ACL_PROPERTY + '.' + _name, interval);
0607:
0608: // Then read the generic access rule list
0609: if (_accessRuleList != null) {
0610: _accessRuleList.dispose();
0611: }
0612: _accessRuleList = createAccessRuleList(runtimeSettings,
0613: ACL_PROPERTY, interval);
0614:
0615: // Initialize the RuntimeProperties object.
0616: getProperties().init(runtimeSettings);
0617:
0618: // Initialize all instances
0619: int count = _manageableObjects.size();
0620: for (int i = 0; i < count; i++) {
0621: Manageable m = (Manageable) _manageableObjects.get(i);
0622: String className = m.getClass().getName();
0623: Log.log_3416(_name, className);
0624: try {
0625: m.init(runtimeSettings);
0626:
0627: // Missing required property
0628: } catch (MissingRequiredPropertyException exception) {
0629: Log.log_3418(_name, className, exception
0630: .getPropertyName(), exception.getDetail());
0631: throw exception;
0632:
0633: // Invalid property value
0634: } catch (InvalidPropertyValueException exception) {
0635: Log.log_3419(_name, className, exception
0636: .getPropertyName(), exception
0637: .getPropertyValue(), exception.getReason());
0638: throw exception;
0639:
0640: // Catch InitializationException and any other exceptions not caught
0641: // by previous catch statements
0642: } catch (Throwable exception) {
0643:
0644: // Log this event
0645: Log.log_3420(exception, _name, className);
0646: if (exception instanceof InitializationException) {
0647: throw (InitializationException) exception;
0648: } else {
0649: throw new InitializationException(exception);
0650: }
0651: }
0652: }
0653:
0654: // Initialize all functions
0655: count = _functionList.size();
0656: for (int i = 0; i < count; i++) {
0657: Function f = (Function) _functionList.get(i);
0658: String functionName = f.getName();
0659: Log.log_3421(_name, functionName);
0660: try {
0661: f.init(runtimeSettings);
0662:
0663: // Missing required property
0664: } catch (MissingRequiredPropertyException exception) {
0665: Log.log_3423(_name, functionName, exception
0666: .getPropertyName(), exception.getDetail());
0667: throw exception;
0668:
0669: // Invalid property value
0670: } catch (InvalidPropertyValueException exception) {
0671: Log.log_3424(_name, functionName, exception
0672: .getPropertyName(), exception
0673: .getPropertyValue(), exception.getReason());
0674: throw exception;
0675:
0676: // Catch InitializationException and any other exceptions not caught
0677: // by previous catch statements
0678: } catch (Throwable exception) {
0679:
0680: // Log this event
0681: Log.log_3425(exception, _name, functionName);
0682:
0683: // Throw an InitializationException. If necessary, wrap around the
0684: // caught exception
0685: if (exception instanceof InitializationException) {
0686: throw (InitializationException) exception;
0687: } else {
0688: throw new InitializationException(exception);
0689: }
0690: }
0691: }
0692:
0693: Log.log_3406(_name);
0694: }
0695:
0696: /**
0697: * Creates the access rule list for the given property.
0698: *
0699: * @param runtimeSettings
0700: * the runtime properties, never <code>null</code>.
0701: *
0702: * @param aclProperty
0703: * the ACL property, never <code>null</code>
0704: *
0705: * @param interval
0706: * the interval in seconds to chack if the ACL file has changed and
0707: * should be reloaded.
0708: *
0709: * @return
0710: * the access rule list created from the property value, never <code>null</code>.
0711: *
0712: * @throws InvalidPropertyValueException
0713: * if the value for the property is invalid.
0714: */
0715: private AccessRuleList createAccessRuleList(
0716: PropertyReader runtimeSettings, String aclProperty,
0717: int interval) throws InvalidPropertyValueException {
0718: String acl = runtimeSettings.get(aclProperty);
0719:
0720: // New access control list is empty
0721: if (acl == null || acl.trim().length() < 1) {
0722: if (aclProperty.equals(ACL_PROPERTY)) {
0723: Log.log_3426(aclProperty);
0724: }
0725: return AccessRuleList.EMPTY;
0726:
0727: // New access control list is non-empty
0728: } else {
0729:
0730: // Parse the new ACL
0731: try {
0732: AccessRuleList accessRuleList = AccessRuleList
0733: .parseAccessRuleList(acl, interval);
0734: int ruleCount = accessRuleList.getRuleCount();
0735: Log.log_3427(ruleCount);
0736: return accessRuleList;
0737:
0738: // Parsing failed
0739: } catch (ParseException exception) {
0740: String exceptionMessage = exception.getMessage();
0741: Log.log_3428(aclProperty, acl, exceptionMessage);
0742: throw new InvalidPropertyValueException(aclProperty,
0743: acl, exceptionMessage);
0744: }
0745: }
0746: }
0747:
0748: /**
0749: * Adds the specified manageable object. It will not immediately be
0750: * bootstrapped and initialized.
0751: *
0752: * @param m
0753: * the manageable object to add, not <code>null</code>.
0754: *
0755: * @throws IllegalStateException
0756: * if this API is currently not bootstrapping.
0757: *
0758: * @throws IllegalArgumentException
0759: * if <code>instance == null</code>.
0760: */
0761: protected final void add(Manageable m)
0762: throws IllegalStateException, IllegalArgumentException {
0763:
0764: // Check state
0765: Manageable.State state = getState();
0766: if (state != BOOTSTRAPPING) {
0767: String message = "State is " + state + " instead of "
0768: + BOOTSTRAPPING + '.';
0769: Utils.logProgrammingError(message);
0770: throw new IllegalStateException(message);
0771: }
0772:
0773: // Check preconditions
0774: MandatoryArgumentChecker.check("m", m);
0775: String className = m.getClass().getName();
0776:
0777: Log.log_3218(_name, className);
0778:
0779: // Store the manageable object in the list
0780: _manageableObjects.add(m);
0781: }
0782:
0783: /**
0784: * Performs shutdown of this XINS API. This method will never throw any
0785: * exception.
0786: */
0787: protected final void deinitImpl() {
0788:
0789: // Deinitialize instances
0790: int count = _manageableObjects.size();
0791: for (int i = 0; i < count; i++) {
0792: Manageable m = (Manageable) _manageableObjects.get(i);
0793:
0794: String className = m.getClass().getName();
0795:
0796: Log.log_3603(_name, className);
0797: try {
0798: m.deinit();
0799: } catch (DeinitializationException exception) {
0800: Log.log_3605(_name, className, exception.getMessage());
0801: } catch (Throwable exception) {
0802: Log.log_3606(exception, _name, className);
0803: }
0804: }
0805: _manageableObjects.clear();
0806:
0807: // Deinitialize functions
0808: count = _functionList.size();
0809: for (int i = 0; i < count; i++) {
0810: Function f = (Function) _functionList.get(i);
0811:
0812: String functionName = f.getName();
0813:
0814: Log.log_3607(_name, functionName);
0815: try {
0816: f.deinit();
0817: } catch (DeinitializationException exception) {
0818: Log.log_3609(_name, functionName, exception
0819: .getMessage());
0820: } catch (Throwable exception) {
0821: Log.log_3610(exception, _name, functionName);
0822: }
0823: }
0824: }
0825:
0826: /**
0827: * Callback method invoked when a function is constructed.
0828: *
0829: * @param function
0830: * the function that is added, not <code>null</code>.
0831: *
0832: * @throws NullPointerException
0833: * if <code>function == null</code>.
0834: *
0835: * @throws IllegalStateException
0836: * if this API state is incorrect.
0837: */
0838: final void functionAdded(Function function)
0839: throws NullPointerException, IllegalStateException {
0840:
0841: // Check state
0842: Manageable.State state = getState();
0843: if (state != UNUSABLE) {
0844: String message = "State is " + state + " instead of "
0845: + UNUSABLE + '.';
0846: Utils.logProgrammingError(message);
0847: throw new IllegalStateException(message);
0848: }
0849:
0850: _functionsByName.put(function.getName(), function);
0851: _functionList.add(function);
0852: }
0853:
0854: /**
0855: * Returns the function with the specified name.
0856: *
0857: * @param name
0858: * the name of the function, will not be checked if it is
0859: * <code>null</code>.
0860: *
0861: * @return
0862: * the function with the specified name, or <code>null</code> if there
0863: * is no match.
0864: */
0865: final Function getFunction(String name) {
0866: return (Function) _functionsByName.get(name);
0867: }
0868:
0869: /**
0870: * Get the specification of the API.
0871: *
0872: * @return
0873: * the {@link APISpec} specification object, never <code>null</code>.
0874: *
0875: * @throws InvalidSpecificationException
0876: * if the specification cannot be found or is invalid.
0877: *
0878: * @since XINS 1.3.0
0879: */
0880: public final APISpec getAPISpecification()
0881: throws InvalidSpecificationException {
0882:
0883: if (_apiSpecification == null) {
0884: String baseURL = _engine.getFileLocation("/WEB-INF/specs/");
0885: _apiSpecification = new APISpec(getClass(), baseURL);
0886: }
0887: return _apiSpecification;
0888: }
0889:
0890: /**
0891: * Determines if the specified IP address is allowed to access the
0892: * specified function, returning a <code>boolean</code> value.
0893: *
0894: * <p>This method finds the first matching rule and then returns the
0895: * <em>allow</em> property of that rule (see
0896: * {@link AccessRule#isAllowRule()}). If there is no matching rule, then
0897: * <code>false</code> is returned.
0898: *
0899: * @param ip
0900: * the IP address, cannot be <code>null</code>.
0901: *
0902: * @param functionName
0903: * the name of the function, cannot be <code>null</code>.
0904: *
0905: * @param conventionName
0906: * the name of the calling convention, can be <code>null</code>.
0907: *
0908: * @return
0909: * <code>true</code> if the request is allowed, <code>false</code> if
0910: * the request is denied.
0911: *
0912: * @throws IllegalArgumentException
0913: * if <code>ip == null || functionName == null</code>.
0914: *
0915: * @since XINS 2.1.
0916: */
0917: public boolean allow(String ip, String functionName,
0918: String conventionName) throws IllegalArgumentException {
0919:
0920: // If no property is defined only localhost is allowed
0921: if (_apiAccessRuleList == AccessRuleList.EMPTY
0922: && _accessRuleList == AccessRuleList.EMPTY
0923: && (ip.equals("127.0.0.1") || ip
0924: .equals(_localIPAddress))) {
0925: return true;
0926: }
0927:
0928: // Match an access rule
0929: Boolean allowed;
0930: try {
0931:
0932: // First check with the API specific one, then use the generic one.
0933: allowed = _apiAccessRuleList.isAllowed(ip, functionName,
0934: conventionName);
0935: if (allowed == null) {
0936: allowed = _accessRuleList.isAllowed(ip, functionName,
0937: conventionName);
0938: }
0939:
0940: // If the IP address cannot be parsed there is a programming error
0941: // somewhere
0942: } catch (ParseException exception) {
0943: String detail = "Malformed IP address: \"" + ip + "\".";
0944: throw Utils.logProgrammingError(detail, exception);
0945: }
0946:
0947: // If there is a match, return the allow-indication
0948: if (allowed != null) {
0949: return allowed.booleanValue();
0950: }
0951:
0952: // No matching access rule match, do not allow
0953: Log.log_3553(ip, functionName, conventionName);
0954: return false;
0955: }
0956:
0957: /**
0958: * Forwards a call to a function, using an IP address. The call will
0959: * actually be handled by
0960: * {@link Function#handleCall(long,FunctionRequest,String)}.
0961: *
0962: * @param start
0963: * the start time of the request, in milliseconds since the
0964: * <a href="http://en.wikipedia.org/wiki/Unix_Epoch">UNIX Epoch</a>.
0965: *
0966: * @param functionRequest
0967: * the function request, never <code>null</code>.
0968: *
0969: * @param ip
0970: * the remote IP address, never <code>null</code>.
0971: *
0972: * @param cc
0973: * the calling convention to use to handle the call, never <code>null</code>.
0974: *
0975: * @return
0976: * the result of the call, never <code>null</code>.
0977: *
0978: * @throws IllegalStateException
0979: * if this object is currently not initialized.
0980: *
0981: * @throws NullPointerException
0982: * if <code>functionRequest == null</code>.
0983: *
0984: * @throws NoSuchFunctionException
0985: * if there is no matching function for the specified request.
0986: *
0987: * @throws AccessDeniedException
0988: * if access is denied for the specified combination of IP address and
0989: * function name.
0990: */
0991: final FunctionResult handleCall(long start,
0992: FunctionRequest functionRequest, String ip,
0993: CallingConvention cc) throws IllegalStateException,
0994: NullPointerException, NoSuchFunctionException,
0995: AccessDeniedException {
0996:
0997: // Check state first
0998: assertUsable();
0999:
1000: // Determine the function name
1001: String functionName = functionRequest.getFunctionName();
1002:
1003: // Check the access rule list
1004: boolean allow = allow(ip, functionName, cc.getConventionName());
1005: if (!allow) {
1006: throw new AccessDeniedException(ip, functionName, cc
1007: .getConventionName());
1008: }
1009:
1010: // Handle meta-functions
1011: FunctionResult result;
1012: if (functionName.length() > 0 && functionName.charAt(0) == '_') {
1013:
1014: // Determine the call ID
1015: int callID;
1016: synchronized (_metaFunctionCallIDs) {
1017: Counter counter = (Counter) _metaFunctionCallIDs
1018: .get(functionName);
1019: if (counter == null) {
1020: throw new NoSuchFunctionException(functionName);
1021: } else {
1022: callID = counter.next();
1023: }
1024: }
1025:
1026: // Call the meta-function
1027: try {
1028: result = callMetaFunction(functionName, functionRequest);
1029: } catch (Throwable exception) {
1030: result = handleFunctionException(start,
1031: functionRequest, ip, callID, exception);
1032: }
1033:
1034: // Log this transaction
1035: long duration = System.currentTimeMillis() - start;
1036: Engine.logTransaction(functionRequest, result, ip, start,
1037: duration);
1038:
1039: // Handle normal functions
1040: } else {
1041: Function function = getFunction(functionName);
1042: if (function == null
1043: && !functionRequest.shouldSkipFunctionCall()) {
1044: throw new NoSuchFunctionException(functionName);
1045: }
1046: if (function == null) {
1047: Object inParams = new FormattedParameters(
1048: functionRequest.getParameters(),
1049: functionRequest.getDataElement());
1050: Log.log_3516(functionRequest.getFunctionName(),
1051: inParams);
1052: result = SUCCESSFUL_RESULT;
1053: } else {
1054: result = function
1055: .handleCall(start, functionRequest, ip);
1056: }
1057: }
1058: return result;
1059: }
1060:
1061: /**
1062: * Handles a call to a meta-function.
1063: *
1064: * @param functionName
1065: * the name of the meta-function, cannot be <code>null</code> and must
1066: * start with the underscore character <code>'_'</code>.
1067: *
1068: * @param functionRequest
1069: * the function request, never <code>null</code>.
1070: *
1071: * @return
1072: * the result of the function call, never <code>null</code>.
1073: *
1074: * @throws NoSuchFunctionException
1075: * if there is no meta-function by the specified name.
1076: */
1077: private FunctionResult callMetaFunction(String functionName,
1078: FunctionRequest functionRequest)
1079: throws NoSuchFunctionException {
1080:
1081: FunctionResult result;
1082:
1083: // No Operation
1084: if ("_NoOp".equals(functionName)) {
1085: result = SUCCESSFUL_RESULT;
1086:
1087: // Retrieve function list
1088: } else if ("_GetFunctionList".equals(functionName)) {
1089: result = doGetFunctionList();
1090:
1091: // Get function call quantity and performance statistics
1092: } else if ("_GetStatistics".equals(functionName)) {
1093:
1094: // Determine value of 'detailed' argument
1095: String detailedArg = functionRequest.getParameters().get(
1096: "detailed");
1097: boolean detailed = !"false".equals(detailedArg);
1098:
1099: // Get the statistics
1100: result = doGetStatistics(detailed);
1101:
1102: // Determine value of 'reset' argument
1103: String resetArg = functionRequest.getParameters().get(
1104: "reset");
1105: boolean reset = "true".equals(resetArg);
1106: if (reset) {
1107: doResetStatistics();
1108: }
1109:
1110: // Get version information
1111: } else if ("_GetVersion".equals(functionName)) {
1112: result = doGetVersion();
1113:
1114: // Check links to underlying systems
1115: } else if ("_CheckLinks".equals(functionName)) {
1116: result = doCheckLinks();
1117:
1118: // Retrieve configuration settings
1119: } else if ("_GetSettings".equals(functionName)) {
1120: result = doGetSettings();
1121:
1122: // Disable a function
1123: } else if ("_DisableFunction".equals(functionName)) {
1124: String disabledFunction = functionRequest.getParameters()
1125: .get("functionName");
1126: result = doDisableFunction(disabledFunction);
1127:
1128: // Enable a function
1129: } else if ("_EnableFunction".equals(functionName)) {
1130: String enabledFunction = functionRequest.getParameters()
1131: .get("functionName");
1132: result = doEnableFunction(enabledFunction);
1133:
1134: // Reset the statistics
1135: } else if ("_ResetStatistics".equals(functionName)) {
1136: result = doResetStatistics();
1137:
1138: // Reload the runtime properties
1139: } else if ("_ReloadProperties".equals(functionName)) {
1140: _engine.reloadPropertiesIfChanged();
1141: result = SUCCESSFUL_RESULT;
1142:
1143: // Retrieve eggs
1144: } else if ("_IWantTheEasterEggs".equals(functionName)) {
1145: result = SUCCESSFUL_RESULT;
1146:
1147: // Return the WSDL description of the API
1148: } else if ("_WSDL".equals(functionName)) {
1149: result = SUCCESSFUL_RESULT;
1150:
1151: // Return the SMD (Simple Method Description) description of the API
1152: } else if ("_SMD".equals(functionName)) {
1153: result = SUCCESSFUL_RESULT;
1154:
1155: // Disable the API
1156: } else if ("_DisableAPI".equals(functionName)) {
1157: _apiDisabled = true;
1158: result = SUCCESSFUL_RESULT;
1159:
1160: // Enable the API
1161: } else if ("_EnableAPI".equals(functionName)) {
1162: _apiDisabled = false;
1163: result = SUCCESSFUL_RESULT;
1164:
1165: // Meta-function does not exist
1166: } else {
1167: throw new NoSuchFunctionException(functionName);
1168: }
1169:
1170: return result;
1171: }
1172:
1173: /**
1174: * Handles an exception caught while a function was executed.
1175: *
1176: * @param start
1177: * the start time of the call, as milliseconds since the
1178: * <a href="http://en.wikipedia.org/wiki/Unix_Epoch">UNIX Epoch</a>.
1179: *
1180: * @param functionRequest
1181: * the request, never <code>null</code>.
1182: *
1183: * @param ip
1184: * the IP address of the requester, never <code>null</code>.
1185: *
1186: * @param callID
1187: * the call identifier, never <code>null</code>.
1188: *
1189: * @param exception
1190: * the exception caught, never <code>null</code>.
1191: *
1192: * @return
1193: * the call result, never <code>null</code>.
1194: */
1195: FunctionResult handleFunctionException(long start,
1196: FunctionRequest functionRequest, String ip, int callID,
1197: Throwable exception) {
1198:
1199: Log.log_3500(exception, _name, callID);
1200:
1201: // Create a set of parameters for the result
1202: BasicPropertyReader resultParams = new BasicPropertyReader();
1203:
1204: // Add the exception class
1205: String exceptionClass = exception.getClass().getName();
1206: resultParams.set("_exception.class", exceptionClass);
1207:
1208: // Add the exception message, if any
1209: String exceptionMessage = exception.getMessage();
1210: if (exceptionMessage != null) {
1211: exceptionMessage = exceptionMessage.trim();
1212: if (exceptionMessage.length() > 0) {
1213: resultParams
1214: .set("_exception.message", exceptionMessage);
1215: }
1216: }
1217:
1218: // Add the stack trace, if any
1219: StringWriter stWriter = new StringWriter(360);
1220: PrintWriter printWriter = new PrintWriter(stWriter);
1221: exception.printStackTrace(printWriter);
1222: String stackTrace = stWriter.toString();
1223: stackTrace = stackTrace.trim();
1224: if (stackTrace.length() > 0) {
1225: resultParams.set("_exception.stacktrace", stackTrace);
1226: }
1227:
1228: return new FunctionResult("_InternalError", resultParams);
1229: }
1230:
1231: /**
1232: * Returns a list of all functions in this API. Per function the name and
1233: * the version are returned.
1234: *
1235: * @return
1236: * the call result, never <code>null</code>.
1237: */
1238: private final FunctionResult doGetFunctionList() {
1239:
1240: // Initialize a builder
1241: FunctionResult builder = new FunctionResult();
1242:
1243: // Loop over all functions
1244: int count = _functionList.size();
1245: for (int i = 0; i < count; i++) {
1246:
1247: // Get some details about the function
1248: Function function = (Function) _functionList.get(i);
1249: String name = function.getName();
1250: String version = function.getVersion();
1251: String enabled = function.isEnabled() ? "true" : "false";
1252:
1253: // Add an element describing the function
1254: ElementBuilder functionElem = new ElementBuilder("function");
1255: functionElem.setAttribute("name", name);
1256: functionElem.setAttribute("version", version);
1257: functionElem.setAttribute("enabled", enabled);
1258: builder.add(functionElem.createElement());
1259: }
1260:
1261: return builder;
1262: }
1263:
1264: /**
1265: * Returns the call statistics for all functions in this API.
1266: *
1267: * @param detailed
1268: * If <code>true</code>, the unsuccessful result will be returned sorted
1269: * per error code. Otherwise the unsuccessful result won't be displayed
1270: * by error code.
1271: *
1272: * @return
1273: * the call result, never <code>null</code>.
1274: */
1275: private final FunctionResult doGetStatistics(boolean detailed) {
1276:
1277: // Initialize a builder
1278: FunctionResult builder = new FunctionResult();
1279:
1280: builder.param("startup", DateConverter.toDateString(_timeZone,
1281: _startupTimestamp));
1282: builder.param("lastReset", DateConverter.toDateString(
1283: _timeZone, _lastStatisticsReset));
1284: builder.param("now", DateConverter.toDateString(_timeZone,
1285: System.currentTimeMillis()));
1286:
1287: // Currently available processors
1288: Runtime rt = Runtime.getRuntime();
1289: try {
1290: builder.param("availableProcessors", String.valueOf(rt
1291: .availableProcessors()));
1292: } catch (NoSuchMethodError error) {
1293: // NOTE: Runtime.availableProcessors() is not available in Java 1.3
1294: }
1295:
1296: // Heap memory statistics
1297: ElementBuilder heap = new ElementBuilder("heap");
1298: long free = rt.freeMemory();
1299: long total = rt.totalMemory();
1300: heap.setAttribute("used", String.valueOf(total - free));
1301: heap.setAttribute("free", String.valueOf(free));
1302: heap.setAttribute("total", String.valueOf(total));
1303: try {
1304: heap.setAttribute("max", String.valueOf(rt.maxMemory()));
1305: } catch (NoSuchMethodError error) {
1306: // NOTE: Runtime.maxMemory() is not available in Java 1.3
1307: }
1308: builder.add(heap.createElement());
1309:
1310: // Function-specific statistics
1311: int count = _functionList.size();
1312: for (int i = 0; i < count; i++) {
1313: Function function = (Function) _functionList.get(i);
1314: FunctionStatistics stats = function.getStatistics();
1315:
1316: ElementBuilder functionElem = new ElementBuilder("function");
1317: functionElem.setAttribute("name", function.getName());
1318:
1319: // Successful
1320: Element successful = stats.getSuccessfulElement();
1321: functionElem.addChild(successful);
1322:
1323: // Unsuccessful
1324: Element[] unsuccessful = stats
1325: .getUnsuccessfulElement(detailed);
1326: for (int j = 0; j < unsuccessful.length; j++) {
1327: functionElem.addChild(unsuccessful[j]);
1328: }
1329:
1330: builder.add(functionElem.createElement());
1331: }
1332:
1333: return builder;
1334: }
1335:
1336: /**
1337: * Returns the XINS version.
1338: *
1339: * @return
1340: * the call result, never <code>null</code>.
1341: */
1342: private final FunctionResult doGetVersion() {
1343:
1344: FunctionResult builder = new FunctionResult();
1345:
1346: builder.param("java.version", System
1347: .getProperty("java.version"));
1348: builder.param("xmlenc.version", org.znerd.xmlenc.Library
1349: .getVersion());
1350: builder.param("xins.version", Library.getVersion());
1351: builder.param("api.version", _apiVersion);
1352:
1353: return builder;
1354: }
1355:
1356: /**
1357: * Returns the links in linked system components. It uses the
1358: * {@link CheckLinks} to connect to each link and builds a
1359: * {@link FunctionResult} which will have the total link count and total
1360: * link failures.
1361: *
1362: * @return
1363: * the call result, never <code>null</code>.
1364: */
1365: private final FunctionResult doCheckLinks() {
1366: return CheckLinks.checkLinks(getProperties().descriptors());
1367: }
1368:
1369: /**
1370: * Returns the settings.
1371: *
1372: * @return
1373: * the call result, never <code>null</code>.
1374: */
1375: private final FunctionResult doGetSettings() {
1376:
1377: FunctionResult builder = new FunctionResult();
1378:
1379: // Build settings
1380: Iterator names = _buildSettings.getNames();
1381: ElementBuilder build = new ElementBuilder("build");
1382: while (names.hasNext()) {
1383: String key = (String) names.next();
1384: String value = _buildSettings.get(key);
1385:
1386: ElementBuilder property = new ElementBuilder("property");
1387: property.setAttribute("name", key);
1388: property.setText(value);
1389: build.addChild(property.createElement());
1390: }
1391: builder.add(build.createElement());
1392:
1393: // Runtime settings
1394: names = _runtimeSettings.getNames();
1395: ElementBuilder runtime = new ElementBuilder("runtime");
1396: while (names.hasNext()) {
1397: String key = (String) names.next();
1398: String value = _runtimeSettings.get(key);
1399:
1400: ElementBuilder property = new ElementBuilder("property");
1401: property.setAttribute("name", key);
1402: property.setText(value);
1403: runtime.addChild(property.createElement());
1404: }
1405: builder.add(runtime.createElement());
1406:
1407: // System properties
1408: Properties sysProps;
1409: try {
1410: sysProps = System.getProperties();
1411: } catch (SecurityException ex) {
1412: Utils.logProgrammingError(ex);
1413: sysProps = new Properties();
1414: }
1415:
1416: Enumeration e = sysProps.propertyNames();
1417: ElementBuilder system = new ElementBuilder("system");
1418: while (e.hasMoreElements()) {
1419: String key = (String) e.nextElement();
1420: String value = sysProps.getProperty(key);
1421:
1422: if (key != null && key.trim().length() > 0 && value != null
1423: && value.trim().length() > 0) {
1424: ElementBuilder property = new ElementBuilder("property");
1425: property.setAttribute("name", key);
1426: property.setText(value);
1427: system.addChild(property.createElement());
1428: }
1429: }
1430: builder.add(system.createElement());
1431:
1432: return builder;
1433: }
1434:
1435: /**
1436: * Enables a function.
1437: *
1438: * @param functionName
1439: * the name of the function to disable, can be <code>null</code>.
1440: *
1441: * @return
1442: * the call result, never <code>null</code>.
1443: */
1444: private final FunctionResult doEnableFunction(String functionName) {
1445:
1446: // Get the name of the function to enable
1447: if (functionName == null || functionName.length() < 1) {
1448: InvalidRequestResult invalidRequest = new InvalidRequestResult();
1449: invalidRequest.addMissingParameter("functionName");
1450: return invalidRequest;
1451: }
1452:
1453: // Get the Function object
1454: Function function = getFunction(functionName);
1455: if (function == null) {
1456: return new InvalidRequestResult();
1457: }
1458:
1459: // Enable or disable the function
1460: function.setEnabled(true);
1461:
1462: return SUCCESSFUL_RESULT;
1463: }
1464:
1465: /**
1466: * Disables a function.
1467: *
1468: * @param functionName
1469: * the name of the function to disable, can be <code>null</code>.
1470: *
1471: * @return
1472: * the call result, never <code>null</code>.
1473: */
1474: private final FunctionResult doDisableFunction(String functionName) {
1475:
1476: // Get the name of the function to disable
1477: if (functionName == null || functionName.length() < 1) {
1478: InvalidRequestResult invalidRequest = new InvalidRequestResult();
1479: invalidRequest.addMissingParameter("functionName");
1480: return invalidRequest;
1481: }
1482:
1483: // Get the Function object
1484: Function function = getFunction(functionName);
1485: if (function == null) {
1486: return new InvalidRequestResult();
1487: }
1488:
1489: // Enable or disable the function
1490: function.setEnabled(false);
1491:
1492: return SUCCESSFUL_RESULT;
1493: }
1494:
1495: /**
1496: * Resets the statistics.
1497: *
1498: * @return
1499: * the call result, never <code>null</code>.
1500: */
1501: private final FunctionResult doResetStatistics() {
1502:
1503: // Remember when we last reset the statistics
1504: _lastStatisticsReset = System.currentTimeMillis();
1505:
1506: // Function-specific statistics
1507: int count = _functionList.size();
1508: for (int i = 0; i < count; i++) {
1509: Function function = (Function) _functionList.get(i);
1510: function.getStatistics().resetStatistics();
1511: }
1512: return SUCCESSFUL_RESULT;
1513: }
1514:
1515: /**
1516: * Indicates whether the API is down for maintenance or not.
1517: *
1518: * @return
1519: * <code>true</code> if the API is disable, <code>false</code> otherwise.
1520: */
1521: boolean isDisabled() {
1522: return _apiDisabled;
1523: }
1524:
1525: /**
1526: * Thread-safe <code>int</code> counter.
1527: *
1528: * @version $Revision: 1.369 $ $Date: 2007/09/18 08:45:06 $
1529: * @author <a href="mailto:ernst@ernstdehaan.com">Ernst de Haan</a>
1530: */
1531: private static final class Counter {
1532:
1533: /**
1534: * The wrapped <code>int</code> number. Initially <code>0</code>.
1535: */
1536: private int _value;
1537:
1538: /**
1539: * Constructs a new <code>Counter</code> that initially returns the
1540: * value <code>0</code>.
1541: */
1542: private Counter() {
1543: // empty
1544: }
1545:
1546: /**
1547: * Retrieves the next value. The first time <code>0</code> is returned,
1548: * the second time <code>1</code>, etc.
1549: *
1550: * @return
1551: * the next sequence number.
1552: */
1553: private synchronized int next() {
1554: return _value++;
1555: }
1556: }
1557: }
|