/*******************************************************************************
* 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.io.FileUtil;
import net.sf.robocode.io.Logger;
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.root.BaseRoot;
import net.sf.robocode.repository.root.IRepositoryRoot;
import net.sf.robocode.repository.root.handlers.RootHandler;
import java.io.*;
import java.net.URLDecoder;
import java.util.*;
/**
* @author Pavel Savara (original)
*/
public class Database {
private Map<String, IRepositoryRoot> roots = new Hashtable<String, IRepositoryRoot>();
private Map<String, IItem> items = new Hashtable<String, IItem>();
private Map<String, IItem> oldItems = new Hashtable<String, IItem>();
private final IRepositoryManager manager;
public Database(IRepositoryManager manager) {
this.manager = manager;
}
public boolean update(File robotsDir, Collection<File> devDirs, boolean force) {
final int prev = items.size();
RootHandler.openHandlers();
Hashtable<String, IRepositoryRoot> newroots = new Hashtable<String, IRepositoryRoot>();
RootHandler.visitDirectories(robotsDir, false, newroots, roots, this, force);
for (File dir : devDirs) {
RootHandler.visitDirectories(dir, true, newroots, roots, this, force);
}
// removed roots
for (IRepositoryRoot oldRoot : roots.values()) {
if (!newroots.containsKey(oldRoot.getURL().toString())) {
moveOldItems(oldRoot);
}
}
roots = newroots;
oldItems = new Hashtable<String, IItem>();
RootHandler.closeHandlers();
return prev != items.size();
}
public boolean update(String file, boolean force) {
final IItem item = items.get(file);
if (item != null) {
item.getRoot().update(item, force);
return true;
}
return false;
}
public void putItem(IItem item) {
final Collection<String> friendlyUrls = item.getFriendlyURLs();
if (friendlyUrls != null) {
for (String friendly : friendlyUrls) {
if (friendly != null) {
final IItem conflict = items.get(friendly);
if (conflict != null) {
if (item.compareTo(conflict) > 0) {
// replace with higher version
items.put(friendly, item);
}
} else {
items.put(friendly, item);
}
}
}
}
}
public IItem getItem(String file) {
IItem item = oldItems.get(file);
if (item == null) {
item = items.get(file);
}
return item;
}
public void moveOldItems(IRepositoryRoot root) {
Collection<Map.Entry<String, IItem>> move = new ArrayList<Map.Entry<String, IItem>>();
for (Map.Entry<String, IItem> entry : items.entrySet()) {
if (entry.getValue().getRoot().equals(root)) {
move.add(entry);
}
}
for (Map.Entry<String, IItem> entry : move) {
String key = entry.getKey();
oldItems.put(key, entry.getValue());
items.remove(key);
}
}
public List<TeamItem> filterTeams(Collection<IRepositoryItem> selectedRobots) {
List<TeamItem> result = new ArrayList<TeamItem>();
for (IRepositoryItem item : selectedRobots) {
if (item.isTeam()) {
result.add((TeamItem) item);
}
}
return result;
}
public List<RobotItem> expandTeams(Collection<IRepositoryItem> selectedRobots) {
List<RobotItem> result = new ArrayList<RobotItem>();
for (IRepositoryItem item : selectedRobots) {
if (item.isTeam()) {
result.addAll(expandTeam((TeamItem) item));
} else {
result.add((RobotItem) item);
}
}
return result;
}
public Collection<RobotItem> expandTeam(TeamItem team) {
Collection<RobotItem> result = new ArrayList<RobotItem>();
StringTokenizer teamTokenizer = new StringTokenizer(team.getMembers(), ",");
while (teamTokenizer.hasMoreTokens()) {
String botNameAndVersion = teamTokenizer.nextToken();
int versionIndex = botNameAndVersion.indexOf(' ');
String botPath = versionIndex < 0 ? botNameAndVersion : botNameAndVersion.substring(0, versionIndex);
botPath = botPath.replace('.', '/');
// first load from same classPath
String teamBot = team.getRoot().getURL() + botPath;
IItem res = getItem(teamBot);
if (res != null && res instanceof RobotItem) {
result.add((RobotItem) res);
continue;
}
// try general search
res = getItem(botNameAndVersion);
if (res != null && res instanceof RobotItem) {
result.add((RobotItem) res);
continue;
}
// no found
Logger.logError("Can't find robot: " + botNameAndVersion);
}
return result;
}
public List<IRepositoryItem> filterSpecifications(boolean onlyWithSource, boolean onlyWithPackage, boolean onlyRobots, boolean onlyDevelopment, boolean onlyNotDevelopment, boolean onlyInJar) {
final List<IRepositoryItem> res = new ArrayList<IRepositoryItem>();
for (IItem item : items.values()) {
final IRepositoryItem spec = (IRepositoryItem) item;
if (!item.isValid()) {
continue;
}
if (onlyWithSource && !spec.isSourceIncluded()) {
continue;
}
if (onlyWithPackage && spec.getFullPackage() == null) {
continue;
}
if (onlyInJar && !spec.isInJAR()) {
continue;
}
if (onlyRobots && !(item instanceof RobotItem)) {
continue;
}
if (onlyDevelopment && !spec.isDevelopmentVersion()) {
continue;
}
if (onlyNotDevelopment && spec.isDevelopmentVersion()) {
continue;
}
if (res.contains(spec)) {
continue;
}
res.add(spec);
}
Collections.sort(res);
return res;
}
public Collection<IRepositoryItem> getAllSpecifications() {
final ArrayList<IRepositoryItem> res = new ArrayList<IRepositoryItem>();
for (IItem item : items.values()) {
final IRepositoryItem spec = (IRepositoryItem) item;
if (!item.isValid()) {
continue;
}
if (!res.contains(spec)) {
res.add(spec);
}
}
return res;
}
public List<IRepositoryItem> getSelectedSpecifications(String selectedRobots) {
List<IRepositoryItem> result = new ArrayList<IRepositoryItem>();
StringTokenizer tokenizer = new StringTokenizer(selectedRobots, ",");
while (tokenizer.hasMoreTokens()) {
String bot = tokenizer.nextToken().trim();
final IItem item = getItem(bot);
if (item != null) {
if (item.isValid()) {
result.add((IRepositoryItem) item);
} else {
Logger.logError("Can't load " + bot + ", because it is invalid robot or team.");
}
} else {
Logger.logError("Can't find " + bot);
}
}
return result;
}
public void save() {
Collection<IItem> uniqueitems = new LinkedList<IItem>();
Collection<IRepositoryRoot> uniqueroots = new LinkedList<IRepositoryRoot>();
for (IItem item : items.values()) {
if (!uniqueitems.contains(item)) {
uniqueitems.add(item);
}
}
for (IRepositoryRoot root : roots.values()) {
uniqueroots.add(root);
}
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream(new File(manager.getRobotsDirectory(), "robot.database"));
oos = new ObjectOutputStream(fos);
oos.writeObject(uniqueroots);
oos.writeObject(uniqueitems);
} catch (IOException e) {
Logger.logError("Can't save robot database", e);
} finally {
FileUtil.cleanupStream(oos);
FileUtil.cleanupStream(fos);
}
}
@SuppressWarnings({ "unchecked"})
public static Database load(IRepositoryManager manager) {
Collection<IItem> uniqueitems;
Collection<IRepositoryRoot> uniqueroots;
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
final File file = new File(manager.getRobotsDirectory(), "robot.database");
if (!file.exists()) {
return null;
}
fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
uniqueroots = (Collection<IRepositoryRoot>) ois.readObject();
uniqueitems = (Collection<IItem>) ois.readObject();
Database res = new Database(manager);
for (IRepositoryRoot root : uniqueroots) {
((BaseRoot) root).setDatabase(res);
String key = root.getURL().toString();
key = URLDecoder.decode(key, "UTF-8");
res.roots.put(key, root);
}
for (IItem item : uniqueitems) {
res.putItem(item);
}
return res;
} catch (Throwable t) {
Logger.logError("Can't load robot database: " + t.getMessage());
return null;
} finally {
FileUtil.cleanupStream(ois);
FileUtil.cleanupStream(fis);
}
}
}