package net.sourceforge.cruisecontrol.dashboard.repository;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXServiceURL;
import net.sourceforge.cruisecontrol.BuildLoopInformation;
import net.sourceforge.cruisecontrol.BuildLoopInformation.ProjectInfo;
import net.sourceforge.cruisecontrol.dashboard.service.JMXConnectorFactory;
public class BuildInformationRepositoryInMemoImpl implements BuildInformationRepository {
private final Map<String, ProjectInfo> data = new HashMap<String, ProjectInfo>();
private final JMXConnectorFactory jmxConnectorFactory;
private final Map<String, BuildLoopInformation> info = new HashMap<String, BuildLoopInformation>();
public BuildInformationRepositoryInMemoImpl() {
this(new JMXConnectorFactory());
}
BuildInformationRepositoryInMemoImpl(JMXConnectorFactory jmxConnectorFactory) {
this.jmxConnectorFactory = jmxConnectorFactory;
}
public ProjectInfo getProjectInfo(String projectName) {
return data.get(projectName);
}
public synchronized ClosableProjectMBeanConnection getJmxConnection(final String projectName) throws IOException {
if (!knowAboutProject(projectName)) {
return null;
}
final JMXConnector jmxConnector
= jmxConnectorFactory.connect(jmxServiceUrl(projectName), environment(projectName));
return new ClosableProjectMBeanConnectionImpl(jmxConnector);
}
public List<ProjectInfo> getProjectInfos() {
return new ArrayList<ProjectInfo>(data.values());
}
public BuildLoopInformation getBuildLoopInfo(final String projectName) {
return buildInfo(projectName);
}
public void saveOrUpdate(final BuildLoopInformation buildLoopInfo) {
final ProjectInfo[] projects = buildLoopInfo.getProjects();
filterDiscontinuedProjects(buildLoopInfo, projects);
for (final ProjectInfo projectInfo : projects) {
data.put(projectInfo.getName(), projectInfo);
info.put(projectInfo.getName(), buildLoopInfo);
}
}
private void filterDiscontinuedProjects(final BuildLoopInformation updatedInfo, final ProjectInfo[] projects) {
final Set<String> currentProjectNames = new HashSet<String>(data.keySet());
for (final String name : currentProjectNames) {
final BuildLoopInformation currentInfo = info.get(name);
if (isSameBuildLoop(updatedInfo, currentInfo) && isMissing(name, projects)) {
info.remove(name);
data.remove(name);
}
}
}
private boolean isSameBuildLoop(final BuildLoopInformation buildLoopInfo,
final BuildLoopInformation currentBuildLoop) {
return currentBuildLoop.getUuid().equals(buildLoopInfo.getUuid());
}
private boolean isMissing(final String projectName, final ProjectInfo[] projects) {
for (final ProjectInfo project : projects) {
if (project.getName().equals(projectName)) {
return false;
}
}
return true;
}
public void removeAll() {
data.clear();
}
public int size() {
return data.size();
}
private Map<String, String> environment(final String projectName) {
Map<String, String> environment = new HashMap<String, String>();
environment.put("java.naming.factory.initial", "com.sun.jndi.rmi.registry.RegistryContextFactory");
environment.put("java.naming.provider.url", getBuildLoopInfo(projectName).getJmxInfo().getRmiUrl());
return environment;
}
private JMXServiceURL jmxServiceUrl(final String projectName) throws MalformedURLException {
final String serviceUrl =
"service:jmx:" + getBuildLoopInfo(projectName).getJmxInfo().getRmiUrl() + "/jndi/jrmp";
return new JMXServiceURL(serviceUrl);
}
private boolean knowAboutProject(final String projectName) {
return info.containsKey(projectName);
}
private BuildLoopInformation buildInfo(final String projectName) {
final BuildLoopInformation buildInfo = info.get(projectName);
if (buildInfo == null) {
throw new RuntimeException("Cannot find build info for project " + projectName);
}
return buildInfo;
}
public boolean hasBuildLoopInfoFor(final String projectName) {
return data.containsKey(projectName);
}
}