/* * Copyright (c) 2009 Craig Sutherland * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using ThoughtWorks.CruiseControl.Remote; using ThoughtWorks.CruiseControl.Remote.Monitor; using NLog; using ThoughtWorks.CruiseControl.Remote.Messages; namespace FastForward.Cache { /// /// Stores the current state about a server. /// public class ServerStateCache : IDisposable { #region Private fields private Logger logger; private CruiseServerClientBase client; private CruiseServerSnapshot currentSnapshot; private PollingServerWatcher watcher; private DatabaseConnection database; #endregion #region Constructors /// /// Initialise a new . /// /// /// /// public ServerStateCache(Logger logger, CruiseServerClientBase client, int interval, DatabaseConnection database) { this.logger = logger; this.client = client; this.database = database; watcher = new PollingServerWatcher(client); watcher.Interval = interval; watcher.Update += (o, e) => { if (e.Exception != null) { logger.Warn("Unable to retrieve snapshot for {0}: {1}", client.Address, e.Exception.Message); } else { logger.Debug("Snapshot updated for {0}", client.Address); currentSnapshot = e.Snapshot; } }; watcher.Refresh(); } #endregion #region Public properties #region Client /// /// The underlying client. /// public CruiseServerClientBase Client { get { return client; } } #endregion #endregion #region Public methods #region Dispose() /// /// Clean up. /// public virtual void Dispose() { watcher.Dispose(); } #endregion #region ProcessMessage() /// /// Process a message onto the remote server. /// /// /// /// public Response ProcessMessage(string action, ServerRequest request) { Response response = null; switch (action) { case "GetCruiseServerSnapshot": response = ReturnServerSnapshot(request); break; case "GetProjectStatus": response = ReturnProjectsSnapshot(request); break; case "GetLog": response = ReturnProjectLog(request as BuildRequest); break; default: response = client.ProcessMessage(action, request); break; } return response; } #endregion #endregion #region Private methods #region ReturnServerSnapshot() /// /// Returns the cached snapshot for the entire server. /// /// /// private Response ReturnServerSnapshot(ServerRequest request) { var response = new SnapshotResponse(request); response.Snapshot = currentSnapshot; response.Result = ResponseResult.Success; return response; } #endregion #region ReturnProjectsSnapshot() /// /// Returns the cached snapshot for the projects. /// /// /// private Response ReturnProjectsSnapshot(ServerRequest request) { var response = new ProjectStatusResponse(request); response.Projects = new List(currentSnapshot.ProjectStatuses); response.Result = ResponseResult.Success; return response; } #endregion #region ReturnProjectLog() /// /// Returns the cached snapshot for the projects. /// /// /// private Response ReturnProjectLog(BuildRequest request) { var response = new DataResponse(request); response.Data = null; // See if the log has already been cached locally using (var reader = database.RetrieveData( "BuildLog", "Server".EqualTo(client.Address) .And("Project".EqualTo(request.ProjectName)) .And("Build".EqualTo(request.BuildName)))) { if ((reader != null) && reader.Read()) { response.Data = reader.GetString(2); } } if (response.Data == null) { // If not, then retrieve the log and cache it var actualLog = client.GetLog(request.ProjectName, request.BuildName); response.Data = actualLog; database.Insert( "BuildLog", new DatabaseValue("Server", client.Address), new DatabaseValue("Project", request.ProjectName), new DatabaseValue("Build", request.BuildName), new DatabaseValue("Log", actualLog)); logger.Info("New log added to cache. Server: {0}, Project: {1}, Build: {2}", client.Address, request.ProjectName, request.BuildName); } response.Result = ResponseResult.Success; return response; } #endregion #endregion } }