/*******************************************************************************
* Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*
* Contributors:
* Pavel Savara
* - Initial implementation
*******************************************************************************/
package net.sf.robocode.repository;
import net.sf.robocode.core.Container;
import net.sf.robocode.io.FileUtil;
import net.sf.robocode.io.Logger;
import net.sf.robocode.io.URLJarCollector;
import net.sf.robocode.repository.items.IItem;
import net.sf.robocode.repository.items.RobotItem;
import net.sf.robocode.repository.items.TeamItem;
import net.sf.robocode.repository.items.BaseItem;
import net.sf.robocode.repository.packager.JarCreator;
import net.sf.robocode.security.HiddenAccess;
import net.sf.robocode.settings.ISettingsListener;
import net.sf.robocode.settings.ISettingsManager;
import net.sf.robocode.ui.IWindowManager;
import net.sf.robocode.version.IVersionManager;
import robocode.control.RobotSpecification;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author Pavel Savara (original)
*/
public class RepositoryManager implements IRepositoryManager {
private final ISettingsManager properties;
private Database db;
public RepositoryManager(ISettingsManager properties) {
this.properties = properties;
properties.addPropertyListener(new SettingsListener());
}
// ------------------------------------------
// interfaces
// ------------------------------------------
public File getRobotsDirectory() {
return FileUtil.getRobotsDir();
}
public List<File> getDevelDirectories() {
List<File> develDirectories = new ArrayList<File>();
for (String path : properties.getOptionsEnabledDevelopmentPaths()) {
try {
develDirectories.add(new File(path).getCanonicalFile());
} catch (IOException e) {
Logger.logError(e);
}
}
return develDirectories;
}
public void refresh(String file) {
if (!db.update(file, true)) {
refresh(true);
}
URLJarCollector.gc();
}
public boolean refresh() {
return refresh(false);
}
public boolean refresh(boolean force) {
boolean refreshed = db.update(getRobotsDirectory(), getDevelDirectories(), force);
if (refreshed) {
setStatus("Saving robot database");
db.save();
}
setStatus("");
URLJarCollector.gc();
return refreshed;
}
public void reload(boolean forced) {
// Bug fix [2867326] - Lockup on start if too many bots in robots dir (cont'd).
URLJarCollector.enableGc(true);
URLJarCollector.gc();
if (forced) {
Logger.logMessage("Rebuilding robot database...");
db = new Database(this);
} else if (db == null) {
setStatus("Reading robot database");
db = Database.load(this);
if (db == null) {
setStatus("Building robot database");
db = new Database(this);
}
}
refresh(true);
setStatus("");
}
public RobotSpecification[] getSpecifications() {
checkDbExists();
final Collection<IRepositoryItem> list = db.getAllSpecifications();
Collection<RobotSpecification> res = new ArrayList<RobotSpecification>();
for (IRepositoryItem s : list) {
res.add(s.createRobotSpecification());
}
return res.toArray(new RobotSpecification[res.size()]);
}
/**
* Expand teams, validate robots
* @param selectedRobots, names of robots and teams, comma separated
* @return robots in teams
*/
public RobotSpecification[] loadSelectedRobots(RobotSpecification[] selectedRobots) {
checkDbExists();
Collection<RobotSpecification> battlingRobotsList = new ArrayList<RobotSpecification>();
int teamNum = 0;
for (RobotSpecification spec: selectedRobots) {
IRepositoryItem item = (IRepositoryItem) HiddenAccess.getFileSpecification(spec);
if (item == null) {
item = getRobot(spec.getNameAndVersion());
}
loadItem(battlingRobotsList, spec, item, teamNum);
teamNum++;
}
return battlingRobotsList.toArray(new RobotSpecification[battlingRobotsList.size()]);
}
/**
* Expand teams, validate robots
* @param selectedRobots, names of robots and teams, comma separated
* @return robots in teams
*/
public RobotSpecification[] loadSelectedRobots(String selectedRobots) {
checkDbExists();
Collection<RobotSpecification> battlingRobotsList = new ArrayList<RobotSpecification>();
final Collection<IRepositoryItem> list = db.getSelectedSpecifications(selectedRobots);
int teamNum = 0;
for (IRepositoryItem item: list) {
loadItem(battlingRobotsList, null, item, teamNum);
teamNum++;
}
return battlingRobotsList.toArray(new RobotSpecification[battlingRobotsList.size()]);
}
private boolean loadItem(Collection<RobotSpecification> battlingRobotsList, RobotSpecification spec, IRepositoryItem item, int teamNum) {
String teamId = String.format("%4d", teamNum);
if (item != null) {
if (item.isTeam()) {
teamId = item.getFullClassNameWithVersion() + "[" + teamId + "]";
final Collection<RobotItem> members = db.expandTeam((TeamItem) item);
for (IRepositoryItem member : members) {
final RobotItem robot = (RobotItem) member;
boolean tested = false;
for (RobotSpecification loaded : battlingRobotsList) {
if (HiddenAccess.getFileSpecification(loaded).equals(robot)) {
tested = true;
break;
}
}
if (tested || robot.validate()) {
battlingRobotsList.add(robot.createRobotSpecification(null, teamId));
}
}
} else {
final RobotItem robot = (RobotItem) item;
if (robot.validate()) {
battlingRobotsList.add(robot.createRobotSpecification(spec, null));
} else {
Logger.logError("Could not load robot: " + robot.getFullClassName());
return false;
}
}
return true;
}
return false;
}
/**
* @param selectedRobots, names of robots and teams, comma separated
* @return robots and teams
*/
public RobotSpecification[] getSelectedRobots(String selectedRobots) {
checkDbExists();
Collection<RobotSpecification> battlingRobotsList = new ArrayList<RobotSpecification>();
final Collection<IRepositoryItem> list = db.getSelectedSpecifications(selectedRobots);
for (IRepositoryItem item: list) {
battlingRobotsList.add(item.createRobotSpecification());
}
return battlingRobotsList.toArray(new RobotSpecification[battlingRobotsList.size()]);
}
public List<IRepositoryItem> getSelectedSpecifications(String selectedRobots) {
checkDbExists();
return db.getSelectedSpecifications(selectedRobots);
}
public List<IRepositoryItem> filterRepositoryItems(boolean onlyWithSource, boolean onlyWithPackage, boolean onlyRobots, boolean onlyDevelopment, boolean onlyNotDevelopment, boolean ignoreTeamRobots, boolean onlyInJar) {
checkDbExists();
return db.filterSpecifications(onlyWithSource, onlyWithPackage, onlyRobots, onlyDevelopment, onlyNotDevelopment,
onlyInJar);
}
public boolean verifyRobotName(String robotName, String shortClassName) {
return RobotItem.verifyRobotName(robotName, shortClassName, true);
}
public int extractJar(IRepositoryItem item) {
if (!item.isInJAR()) {
return -2;
}
((BaseItem) item).getRoot().extractJAR();
return 0;
}
public void createTeam(File target, URL web, String desc, String author, String members, String teamVersion) throws IOException {
checkDbExists();
final String ver = Container.getComponent(IVersionManager.class).getVersion();
TeamItem.createOrUpdateTeam(target, web, desc, author, members, teamVersion, ver);
refresh(target.toURI().toString());
}
public String createPackage(File target, URL web, String desc, String author, String version, boolean source, List<IRepositoryItem> selectedRobots) {
checkDbExists();
final List<RobotItem> robots = db.expandTeams(selectedRobots);
final List<TeamItem> teams = db.filterTeams(selectedRobots);
final String res = JarCreator.createPackage(target, source, robots, teams, web, desc, author, version);
refresh(target.toURI().toString());
return res;
}
private IRepositoryItem getRobot(String fullClassNameWithVersion) {
final IItem item = db.getItem(fullClassNameWithVersion);
if (item == null || !item.isValid()) {
return null;
}
return (IRepositoryItem) item;
}
private void setStatus(String message) {
IWindowManager windowManager = Container.getComponent(IWindowManager.class);
if (windowManager != null) {
windowManager.setStatus(message);
}
if (message.length() > 0) {
Logger.logMessage(message);
}
}
private void checkDbExists() {
if (db == null) {
reload(false);
}
}
// ------------------------------------------
// settings listener
// ------------------------------------------
private class SettingsListener implements ISettingsListener {
private Collection<String> lastEnabledDevelPaths;
public void settingChanged(String property) {
if (property.equals(ISettingsManager.OPTIONS_DEVELOPMENT_PATH)
|| property.equals(ISettingsManager.OPTIONS_DEVELOPMENT_PATH_EXCLUDED)) {
Collection<String> enabledDevelPaths = properties.getOptionsEnabledDevelopmentPaths();
if (lastEnabledDevelPaths == null || !enabledDevelPaths.equals(lastEnabledDevelPaths)) {
lastEnabledDevelPaths = enabledDevelPaths;
reload(false);
}
}
}
}
}