package com.rayo.server.admin; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.jar.Attributes; import java.util.jar.Manifest; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import com.rayo.server.listener.AdminListener; import com.voxeo.logging.Loggerf; /** * <p>The admin service lets internal services or external applications to execute * operations on a Rayo Server or Gateway. This base abstract class defines * common operations that will implement the particular server and gateway * admin interfaces.</p> * * <p>External applications will normally use JMX operations to invoke methods * on this admin service.</p> * * @author martin * */ public abstract class AdminService { private static final Loggerf log = Loggerf.getLogger(AdminService.class); public static final String GATEWAY_DOMAIN = "gateway-domain"; public static final String DEFAULT_PLATFORM_ID = "default-platform-id"; public static final String WEIGHT = "weight"; public static final String PRIORITY = "priority"; private long buildNumber; private String buildId; private String versionNumber; private List<AdminListener> adminListeners = new ArrayList<AdminListener>(); private AtomicBoolean quiesceMode = new AtomicBoolean(false); private ReentrantReadWriteLock adminLock = new ReentrantReadWriteLock(); /** * <p>Returns the Quiesce status for this particular Rayo Server or Gateway.</p> * * @return boolean Quiesce status */ public boolean isQuiesceMode() { Lock lock = adminLock.readLock(); lock.lock(); try { return quiesceMode.get(); } finally { lock.unlock(); } } /** * <p>Disables Quiesce mode. Once Quiesce mode is disabled the Rayo server or * Gateway becomes fully active and it will start processing calls and messages * again.</p> */ public void disableQuiesce() { Lock lock = adminLock.writeLock(); lock.lock(); try { log.info("Quiesce Mode has been DISABLED"); quiesceMode.set(false); for (AdminListener listener: getAdminListeners()) { listener.onQuiesceModeExited(); } } finally { lock.unlock(); } } /** * <p>Enables Quiesce mode. On Quiesce mode the Rayo Server or Gateway will not * process any more calls or messages. Any particular calls or messages that are * currently being processed while the Rayo Server or Gateway goes into Quiesce * mode will still continue to be processed.</p> */ public void enableQuiesce() { Lock lock = adminLock.writeLock(); lock.lock(); try { log.info("Quiesce Mode has been ENABLED"); quiesceMode.set(true); for (AdminListener listener: getAdminListeners()) { listener.onQuiesceModeEntered(); } } finally { lock.unlock(); } } /** * <p>Returns the Quiesce status for this particular Rayo Server or Gateway.</p> * * @return boolean Quiesce status */ public boolean getQuiesceMode() { return isQuiesceMode(); } /** * <p>Shuts down a Rayo Server or Gateway.</p> */ public void shutdown() { for (AdminListener listener: adminListeners) { listener.onShutdown(); } adminListeners.clear(); } /** * <p>Returns the build number of the Rayo Server or Gateway.</p> * * @return long Build number */ public long getBuildNumber() { return buildNumber; } /** * <p>Reads the context configuration from the Servlet Context. Typical * context configuration are the build number, build id or version number. * * @param config Servlet config */ public void readConfigurationFromContext(ServletConfig config) { ServletContext application = config.getServletContext(); InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF"); try { Manifest manifest = new Manifest(inputStream); Attributes attributes = manifest.getMainAttributes(); String buildNumber = attributes.getValue("Hudson-Build-Number"); if (buildNumber != null) { this.buildNumber = Long.parseLong(buildNumber); log.info("Build Number: %s", buildNumber); } this.buildId = attributes.getValue("Build-Id"); log.info("Build Id: %s", buildId); this.versionNumber = attributes.getValue("Specification-Version"); log.info("Build Version Number: %s", versionNumber); } catch (IOException e) { log.warn("Could not red MANIFEST.MF file. Application information won't be available in Admin Service."); } } /** * Returns the id of the Rayo Server or Gateway build * * @return String Build id */ public String getBuildId() { return buildId; } /** * Returns the version number of the Rayo Server or Gateway * * @return String Version number */ public String getVersionNumber() { return versionNumber; } /** * Returns the list of the admin listeners that have been added to * this Admin Service * * @return Collection<AdminListener> Listeners */ protected Collection<AdminListener> getAdminListeners() { return new ArrayList<AdminListener>(adminListeners); } /** * Adds an admin listener to this Admin Service. Admin listeners will * be notified about any events on the AdminService like for example * when the Quiesce status changes or when the server is shut down. * * @param listener Admin listener */ public void addAdminListener(AdminListener listener) { adminListeners.add(listener); } /** * Removes an admin listener from this Admin Service * * @param listener Listener */ public void removeAdminListener(AdminListener listener) { adminListeners.remove(listener); } /** * Returns the name of this Rayo Server or Gateway * * @return String name of the server */ public abstract String getServerName(); }