//
// Copyright 2010 Cinch Logic Pty Ltd.
//
// http://www.chililog.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package org.chililog.server.engine;
import java.util.ArrayList;
import org.bson.types.ObjectId;
import org.chililog.server.common.ChiliLogException;
import org.chililog.server.common.Log4JLogger;
import org.chililog.server.data.MongoConnection;
import org.chililog.server.data.RepositoryConfigBO;
import org.chililog.server.data.RepositoryConfigController;
import org.chililog.server.data.RepositoryConfigListCriteria;
import org.chililog.server.data.RepositoryConfigBO.Status;
import com.mongodb.DB;
/**
* <p>
* The RepositoryService is responsible managing for start/stop/reload all repositories.
* </p>
*
* <pre>
* // Start all repositories
* RepositoryManager.getInstance().start();
*
* // Stop all repositories
* RepositoryManager.getInstance().stop();
* </pre>
*
* <p>
* It is assumed that mongoDB and HornetQ (via {@link MqService}) has been started.
* </p>
*
* @author vibul
*
*/
public class RepositoryService {
static Log4JLogger _logger = Log4JLogger.getLogger(RepositoryService.class);
/**
* List of repositories that are readonly or online
*/
private ArrayList<Repository> _activeRepositories = new ArrayList<Repository>();
/**
* Returns the singleton instance for this class
*/
public static RepositoryService getInstance() {
return SingletonHolder.INSTANCE;
}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance() or the first access to
* SingletonHolder.INSTANCE, not before.
*
* @see http://en.wikipedia.org/wiki/Singleton_pattern
*/
private static class SingletonHolder {
public static final RepositoryService INSTANCE = new RepositoryService();
}
/**
* <p>
* Singleton constructor
* </p>
*/
private RepositoryService() {
return;
}
/**
* <p>
* Starts this service by starting all repositories where the startup status is ONLINE
* </p>
* <p>
* Should be called once at the start of the application
* </p>
*/
public synchronized void start() throws ChiliLogException {
ArrayList<RepositoryConfigBO> repoConfigList = this.getRepositoryConfigList();
for (RepositoryConfigBO repoConfig : repoConfigList) {
if (repoConfig.getStartupStatus() == Status.ONLINE) {
bringRepositoryOnline(repoConfig);
} else if (repoConfig.getStartupStatus() == Status.READONLY) {
makeRepositoryReadOnly(repoConfig);
}
}
return;
}
/**
* Stops this service
*
* @throws Exception
*/
public synchronized void stop() throws Exception {
takeAllRepositoriesOffline();
return;
}
/**
* <p>
* Brings all repositories online
* </p>
*/
public synchronized void bringAllRepositoriesOnline() throws ChiliLogException {
ArrayList<RepositoryConfigBO> repoList = this.getRepositoryConfigList();
for (RepositoryConfigBO repoConfig : repoList) {
// If offline or readonly, enable it
Repository repo = getActiveRepository(repoConfig.getDocumentID());
if (repo == null) {
bringRepositoryOnline(repoConfig);
} else if (repo.getStatus() == Status.READONLY) {
// Reload readonly repositories so that it gets the latest definition
takeRepositoryOffline(repo);
makeRepositoryReadOnly(repoConfig);
}
}
return;
}
/**
* <p>
* Make all repositories read only
* </p>
*/
public synchronized void makeAllRepositoriesReadonly() throws ChiliLogException {
ArrayList<RepositoryConfigBO> repoList = this.getRepositoryConfigList();
for (RepositoryConfigBO repoConfig : repoList) {
// If offline or readonly, enable it
Repository repo = getActiveRepository(repoConfig.getDocumentID());
if (repo == null) {
makeRepositoryReadOnly(repoConfig);
} else if (repo.getStatus() == Status.ONLINE) {
repo.makeReadonly();
}
}
return;
}
/**
* <p>
* Take all repositories offline
* </p>
*/
public synchronized void takeAllRepositoriesOffline() throws ChiliLogException {
for (Repository repo : _activeRepositories) {
repo.takeOffline();
}
_activeRepositories.clear();
return;
}
/**
* Starts the specified repository. Once started, a repository becomes "online". Log entries will be streamed and
* saved (if configured to do so).
*
* @param repositoryInfoDocumentID
* Document ID of the repository info to start
* @return Repository runtime information
* @throws ChiliLogException
*/
public synchronized Repository bringRepositoryOnline(ObjectId repositoryInfoDocumentID) throws ChiliLogException {
Repository repo = this.getActiveRepository(repositoryInfoDocumentID);
if (repo != null) {
if (repo.getStatus() == Status.ONLINE) {
// Repository is already online
return repo;
} else if (repo.getStatus() == Status.READONLY) {
// Remove the repository so we can bring online with the latest definition
_activeRepositories.remove(repo);
}
}
DB db = MongoConnection.getInstance().getConnection();
RepositoryConfigBO repoInfo = RepositoryConfigController.getInstance().get(db, repositoryInfoDocumentID);
return bringRepositoryOnline(repoInfo);
}
/**
* Creates the specified repository and brings it online
*
* @param repoConfig
* Meta data of repository to bring online
* @return Repository runtime information
* @throws ChiliLogException
*/
private Repository bringRepositoryOnline(RepositoryConfigBO repoConfig) throws ChiliLogException {
Repository repo = new Repository(repoConfig);
repo.bringOnline();
_activeRepositories.add(repo);
return repo;
}
/**
* Creates a repository and make it readonly
*
* @param repositoryInfoDocumentID
* Document ID of the repository to stop
* @return Repository runtime information
* @throws ChiliLogException
*/
public synchronized Repository makeRepositoryReadOnly(ObjectId repositoryInfoDocumentID) throws ChiliLogException {
Repository repo = this.getActiveRepository(repositoryInfoDocumentID);
if (repo != null) {
if (repo.getStatus() == Status.ONLINE) {
// Make repository readonly
repo.makeReadonly();
return repo;
} else if (repo.getStatus() == Status.READONLY) {
// Repo already readonly so just return it
return repo;
}
}
DB db = MongoConnection.getInstance().getConnection();
RepositoryConfigBO repoInfo = RepositoryConfigController.getInstance().get(db, repositoryInfoDocumentID);
return makeRepositoryReadOnly(repoInfo);
}
/**
* Creates a repository and make it readonly
*
* @param repoConfig
* Runtime information of repository to make readonly
* @return Repository runtime information
* @throws ChiliLogException
*/
private synchronized Repository makeRepositoryReadOnly(RepositoryConfigBO repoConfig) throws ChiliLogException {
Repository repo = new Repository(repoConfig);
repo.makeReadonly();
_activeRepositories.add(repo);
return repo;
}
/**
* Take the specified repository offline. Streaming of log entries will be disabled and new log entries will not be
* stored. Also, searching is prohibited on the workbench.
*
* @param repositoryInfoDocumentID
* Document ID of the repository to stop
* @throws ChiliLogException
*/
public synchronized void takeRepositoryOffline(ObjectId repositoryInfoDocumentID) throws ChiliLogException {
Repository repo = getActiveRepository(repositoryInfoDocumentID);
if (repo != null) {
takeRepositoryOffline(repo);
}
}
/**
* Take the specified repository off line. Streaming of log entries will be disabled and new log entries will not be
* stored. Also, searching is prohibited on the workbench.
*
* @param repo
* Runtime information of repository to stop
* @throws ChiliLogException
*/
private synchronized void takeRepositoryOffline(Repository repo) throws ChiliLogException {
repo.takeOffline();
_activeRepositories.remove(repo);
return;
}
/**
* Finds an online repository with a matching repository configuration document id
*
* @param repositoryConfigDocumentID
* ID of repository configuration document of repository to find
* @return Matching repository. <code>null</code> if not found
*/
private Repository getActiveRepository(ObjectId repositoryConfigDocumentID) {
for (Repository repo : _activeRepositories) {
if (repo.getRepoConfig().getDocumentID().equals(repositoryConfigDocumentID)) {
return repo;
}
}
return null;
}
/**
* <p>
* Returns a list of repository configuration
* </p>
*
* @throws ChiliLogException
*/
private ArrayList<RepositoryConfigBO> getRepositoryConfigList() throws ChiliLogException {
// Get count connections
DB db = MongoConnection.getInstance().getConnection();
// Get list of repositories
RepositoryConfigListCriteria criteria = new RepositoryConfigListCriteria();
ArrayList<RepositoryConfigBO> list = RepositoryConfigController.getInstance().getList(db, criteria);
return list;
}
/**
* Returns the latest runtime information for the specified repository info id.
*
* @param id
* Repository config document id of the repository to retrieve
* @return Matching repository.
* @throws ChiliLogException
* - if error or not found
*/
public synchronized Repository getRepository(ObjectId id) throws ChiliLogException {
// Check it see if repository is online
for (Repository repo : _activeRepositories) {
if (repo.getRepoConfig().getDocumentID().equals(id)) {
return repo;
}
}
// Get count connections
DB db = MongoConnection.getInstance().getConnection();
RepositoryConfigBO repoConfig = RepositoryConfigController.getInstance().get(db, id);
return repoConfig == null ? null : new Repository(repoConfig);
}
/**
* Returns the latest runtime information for all repositories
*
* @throws ChiliLogException
*/
public synchronized Repository[] getRepositories() throws ChiliLogException {
ArrayList<Repository> list = new ArrayList<Repository>();
ArrayList<RepositoryConfigBO> repoConfigList = this.getRepositoryConfigList();
for (RepositoryConfigBO repoConfig : repoConfigList) {
Repository repo = getActiveRepository(repoConfig.getDocumentID());
if (repo == null) {
list.add(new Repository(repoConfig));
} else {
// Online so send that one
list.add(repo);
}
}
return list.toArray(new Repository[] {});
}
}