All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.sf.robocode.repository.items.RobotItem Maven / Gradle / Ivy
/*
* Copyright (c) 2001-2023 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
* https://robocode.sourceforge.io/license/epl-v10.html
*/
package net.sf.robocode.repository.items;
import net.sf.robocode.io.FileUtil;
import net.sf.robocode.io.Logger;
import net.sf.robocode.io.RobocodeProperties;
import net.sf.robocode.io.URLJarCollector;
import static net.sf.robocode.io.Logger.logError;
import net.sf.robocode.repository.IRobotItem;
import net.sf.robocode.repository.RobotProperties;
import net.sf.robocode.repository.RobotType;
import net.sf.robocode.repository.root.ClasspathRoot;
import net.sf.robocode.repository.root.IRepositoryRoot;
import net.sf.robocode.security.HiddenAccess;
import net.sf.robocode.core.Container;
import net.sf.robocode.host.IHostManager;
import net.sf.robocode.version.IVersionManager;
import robocode.control.RobotSpecification;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashSet;
import java.util.Set;
/**
* @author Pavel Savara (original)
* @author Flemming N. Larsen (contributor)
*/
public class RobotItem extends RobotSpecItem implements IRobotItem {
private static final long serialVersionUID = 1L;
// Allowed maximum length for a robot's full package name
private static final int MAX_FULL_PACKAGE_NAME_LENGTH = 32;
// Allowed maximum length for a robot's short class name
private static final int MAX_SHORT_CLASS_NAME_LENGTH = 32;
protected static final String ROBOT_PLATFORM = "robot.platform";
private static final String ROBOT_CLASSNAME = "robot.classname";
private static final String ROBOT_VERSION = "robot.version";
private static final String ROBOT_DESCRIPTION = "robot.description";
private static final String ROBOT_AUTHOR_NAME = "robot.author.name";
private static final String ROBOT_WEBPAGE = "robot.webpage";
private static final String ROBOCODE_VERSION = "robocode.version";
private static final String ROBOT_INCLUDE_SOURCE = "robot.include.source";
private static final String ROBOT_INCLUDE_DATA = "robot.include.data";
private static final String ROBOT_CODESIZE = "robot.codesize";
// File extensions
private static final String CLASS_EXTENSION = ".class";
private static final String PROPERTIES_EXTENSION = ".properties";
private static final String HTML_EXTENSION = ".html";
private static final boolean ALWAYS_USE_CACHE_FOR_DATA = System.getProperty("ALWAYSUSECACHEFORDATA", "false").equals(
"true");
private RobotType robotType;
private URL classPathURL;
private final Set sourcePathURLs; // This is a Set in order to avoid duplicates
private URL classURL;
private URL propertiesURL;
private String className;
protected boolean isPropertiesLoaded;
public RobotItem(URL itemURL, IRepositoryRoot root) {
super(itemURL, root);
isValid = true;
classPathURL = root.getURL();
sourcePathURLs = new HashSet();
}
private void populate() {
populatePropertiesURLFromClassURL();
populateClassURLFromPropertiesURL();
loadProperties();
}
public void setClassURL(URL classUrl) {
this.classURL = classUrl;
populate();
}
public void setPropertiesURL(URL propertiesUrl) {
this.propertiesURL = propertiesUrl;
populate();
}
public void setClassPathURL(URL classPathUrl) {
this.classPathURL = classPathUrl;
}
public void addSourcePathURL(URL sourcePathUrl) {
sourcePathURLs.add(sourcePathUrl);
}
// -------------------------------------
// URL initialization
// -------------------------------------
private void populatePropertiesURLFromClassURL() {
if (propertiesURL == null && classURL != null) {
final String path = classURL.toString().replaceFirst("\\" + CLASS_EXTENSION, PROPERTIES_EXTENSION);
try {
propertiesURL = new URL(path);
} catch (MalformedURLException e) {
Logger.logError(e);
}
if (isInvalidURL(propertiesURL)) {
propertiesURL = null;
}
}
}
private void populateClassURLFromPropertiesURL() {
if (classURL == null && propertiesURL != null) {
final String path = propertiesURL.toString().replaceAll("\\" + PROPERTIES_EXTENSION, CLASS_EXTENSION);
try {
classURL = new URL(path);
} catch (MalformedURLException e) {
Logger.logError(e);
}
if (isInvalidURL(classURL)) {
classURL = null;
}
}
}
private void populateClassNameFromClassURL() {
populate();
if (className == null && classURL != null) {
final String path = classURL.toString();
// .dll file?
int index = (path.toLowerCase().indexOf(".dll!/"));
if (index > 0) {
className = path.substring(index + 6);
return;
}
// Class within .jar or regular file path?
index = path.lastIndexOf('!');
if (index > 0) {
// .jar file
className = path.substring(index + 2);
} else {
// file path
className = path.substring(root.getURL().toString().length());
}
// Remove the file extension from the class name
index = className.lastIndexOf('.');
if (index > 0) {
className = className.substring(0, index);
}
// Replace all file separators with dots (from file path the package/namespace)
className = className.replaceAll("[\\\\\\/]", ".");
}
}
private void populateHtmlURL() {
populate();
if (htmlURL == null && classURL != null) {
try {
htmlURL = new URL(classURL.toString().replaceFirst(CLASS_EXTENSION, HTML_EXTENSION));
} catch (MalformedURLException ignore) {}
}
if (htmlURL == null && propertiesURL != null) {
try {
htmlURL = new URL(propertiesURL.toString().replaceFirst(PROPERTIES_EXTENSION, HTML_EXTENSION));
} catch (MalformedURLException ignore) {}
}
if (isInvalidURL(htmlURL)) {
htmlURL = null;
}
}
private boolean isInvalidURL(URL url) {
if (url != null) {
InputStream is = null;
try {
URLConnection conn = URLJarCollector.openConnection(url);
is = conn.getInputStream();
return false;
} catch (IOException e) {
return true;
} finally {
FileUtil.cleanupStream(is);
}
}
return true;
}
// / -------------------------------------
// / public
// / -------------------------------------
public boolean isTeam() {
return false;
}
public URL getHtmlURL() {
// Lazy
if (htmlURL == null) {
populateHtmlURL();
}
return htmlURL;
}
public URL getPropertiesURL() {
if (propertiesURL == null) {
populatePropertiesURLFromClassURL();
}
return propertiesURL;
}
public Set getFriendlyURLs() {
populate();
Set urls = new HashSet();
URL url = null;
if (classURL != null) {
url = classURL;
} else if (propertiesURL != null) {
url = propertiesURL;
}
if (url != null) {
String sUrl = url.toString();
String urlNoType = sUrl.substring(0, sUrl.lastIndexOf('.'));
String path = url.getPath();
String pathNoType = path.substring(0, path.lastIndexOf('.'));
urls.add(urlNoType);
urls.add(pathNoType);
}
if (getFullClassName() != null) {
if (RobocodeProperties.isTestingOn()) {
urls.add(getFullClassName());
} else {
urls.add(getUniqueFullClassName());
}
urls.add(getUniqueFullClassNameWithVersion());
}
if (root.isJAR()) {
urls.add(root.getURL().toString());
}
if (root instanceof ClasspathRoot) {
String friendly = ((ClasspathRoot) root).getFriendlyProjectURL(itemUrl);
if (friendly != null) {
urls.add(friendly);
}
}
return urls;
}
/**
* {@inheritDoc}
*/
public void update(long lastModified, boolean force) {
if (lastModified > this.lastModified || force) {
if (force) {
isValid = true;
}
if (isValid) {
validateType(false);
}
this.lastModified = lastModified;
if (classURL == null) {
isValid = false;
}
loadProperties();
if (!isTeamRobot() && root.isJAR() && !isPropertiesLoaded) {
isValid = false;
}
if (isValid) {
verifyName();
}
}
}
protected void validateType(boolean resolve) {
populate();
final IHostManager hostManager = Container.getComponent(IHostManager.class);
robotType = hostManager.getRobotType(this, resolve, classURL != null);
if (!robotType.isValid()) {
isValid = false;
}
}
// Stronger than update
public boolean validate() {
validateType(true);
return isValid;
}
// Note that ROBOCODE_CLASSNAME can be invalid, an hence can't be trusted when loaded!
// Hence, we read the fullClassName field instead and NOT the ROBOCODE_CLASSNAME property.
private boolean loadProperties() {
if (!isPropertiesLoaded && propertiesURL != null) {
InputStream ios = null;
try {
URLConnection con = URLJarCollector.openConnection(propertiesURL);
ios = con.getInputStream();
properties.load(ios);
isPropertiesLoaded = true;
return true;
} catch (IOException e) {
return false;
} finally {
FileUtil.cleanupStream(ios);
}
}
return false;
}
private boolean verifyName() {
String robotName = getFullClassName();
String shortClassName = getShortClassName();
final boolean valid = verifyRobotName(robotName, shortClassName, false);
if (!valid) {
isValid = false;
}
return valid;
}
public static boolean verifyRobotName(String fullClassName, String shortClassName, boolean silent) {
if (fullClassName == null || fullClassName.length() == 0 || fullClassName.contains("$")) {
return false;
}
int lIndex = fullClassName.indexOf(".");
if (lIndex > 0) {
String rootPackage = fullClassName.substring(0, lIndex);
if (rootPackage.equalsIgnoreCase("robocode")) {
if (!silent) {
logError("Robot " + fullClassName + " ignored. You cannot use package " + rootPackage);
}
return false;
}
if (rootPackage.length() > MAX_FULL_PACKAGE_NAME_LENGTH) {
if (!silent) {
logError(
"Robot " + fullClassName + " has package name too long. " + MAX_FULL_PACKAGE_NAME_LENGTH
+ " characters maximum please.");
}
return false;
}
}
if (shortClassName != null && shortClassName.length() > MAX_SHORT_CLASS_NAME_LENGTH) {
if (!silent) {
logError(
"Robot " + fullClassName + " has classname too long. " + MAX_SHORT_CLASS_NAME_LENGTH
+ " characters maximum please.");
}
return false;
}
return true;
}
public void storeProperties(OutputStream os, RobotProperties robotProps) throws IOException {
if (className != null) {
properties.setProperty(ROBOT_CLASSNAME, className);
}
if (robotProps.getVersion() != null) {
properties.setProperty(ROBOT_VERSION, robotProps.getVersion());
}
if (robotProps.getDescription() != null) {
properties.setProperty(ROBOT_DESCRIPTION, robotProps.getDescription());
}
if (robotProps.getAuthor() != null) {
properties.setProperty(ROBOT_AUTHOR_NAME, robotProps.getAuthor());
}
if (robotProps.getWebPage() != null) {
properties.setProperty(ROBOT_WEBPAGE, robotProps.getWebPage().toExternalForm());
}
if (robotProps.getCodeSize() != null) {
properties.setProperty(ROBOT_CODESIZE, "" + robotProps.getCodeSize());
}
properties.setProperty(ROBOT_INCLUDE_SOURCE, "" + robotProps.isIncludeSource());
String version = Container.getComponent(IVersionManager.class).getVersion();
properties.setProperty(ROBOCODE_VERSION, version);
saveProperties(os);
saveProperties();
}
private void saveProperties(OutputStream os) throws IOException {
properties.store(os, "Robocode Robot");
}
private void saveProperties() {
File file = new File(root.getPath(), className.replaceAll("\\.", "/") + PROPERTIES_EXTENSION);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
saveProperties(fos);
} catch (IOException e) {
e.printStackTrace();
} finally {
FileUtil.cleanupStream(fos);
}
populatePropertiesURLFromClassURL();
}
public boolean isJuniorRobot() {
return robotType.isJuniorRobot();
}
public boolean isStandardRobot() {
return robotType.isStandardRobot();
}
public boolean isAdvancedRobot() {
return robotType.isAdvancedRobot();
}
public boolean isTeamRobot() {
return robotType.isTeamRobot();
}
public boolean isDroid() {
return robotType.isDroid();
}
public boolean isSentryRobot() {
return robotType.isSentryRobot();
}
public boolean isInteractiveRobot() {
return robotType.isInteractiveRobot();
}
public boolean isPaintRobot() {
return robotType.isPaintRobot();
}
public URL getClassPathURL() {
return classPathURL;
}
public URL[] getSourcePathURLs() {
// If no source path URL exists, we must use the class path URL
if (sourcePathURLs.size() == 0) {
return new URL[] { classPathURL };
}
return sourcePathURLs.toArray(new URL[] {});
}
public String getFullClassName() {
// Lazy
if (className == null) {
populateClassNameFromClassURL();
}
return className;
}
public String getVersion() {
return properties.getProperty(ROBOT_VERSION, null);
}
public String getDescription() {
return properties.getProperty(ROBOT_DESCRIPTION, null);
}
public String getAuthorName() {
return properties.getProperty(ROBOT_AUTHOR_NAME, null);
}
public String getPlatform() {
return properties.getProperty(ROBOT_PLATFORM, "Java");
}
public URL getWebpage() {
try {
String webPage = properties.getProperty(ROBOT_WEBPAGE, null);
if (webPage == null || webPage.trim().isEmpty()) {
return null;
}
return new URL(webPage);
} catch (MalformedURLException e) {
return null;
}
}
public Integer getCodeSize() {
String value = properties.getProperty(ROBOT_CODESIZE);
if (value == null) {
return null;
}
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return null;
}
}
public boolean getIncludeSource() {
return properties.getProperty(ROBOT_INCLUDE_SOURCE, "true").equalsIgnoreCase("true");
}
public boolean getIncludeData() {
return properties.getProperty(ROBOT_INCLUDE_DATA, "true").equalsIgnoreCase("true");
}
public boolean isSourceIncluded() {
return sourcePathURLs.size() > 0;
}
public String getRobocodeVersion() {
return properties.getProperty(ROBOCODE_VERSION, null);
}
public String getReadableDirectory() {
String path;
if (root.isJAR()) {
String jarFile = getClassPathURL().getFile();
jarFile = jarFile.substring(jarFile.lastIndexOf('/') + 1);
path = FileUtil.getRobotsDataDir().getPath();
if (jarFile.length() > 0) {
path += File.separator + jarFile + '_';
}
} else {
path = getClassPathURL().getFile();
}
if (getFullPackage() != null) {
path += File.separator + getFullPackage().replace('.', File.separatorChar);
}
return path;
}
public String getWritableDirectory() {
String path;
if (root.isJAR()) {
String jarFile = getClassPathURL().getFile();
jarFile = jarFile.substring(jarFile.lastIndexOf('/') + 1);
path = FileUtil.getRobotsDataDir().getPath();
if (jarFile.length() > 0) {
path += File.separator + jarFile + '_';
}
} else {
path = ALWAYS_USE_CACHE_FOR_DATA ? FileUtil.getRobotsDataDir().getPath() : getClassPathURL().getFile();
}
if (getFullPackage() != null) {
path += File.separator + getFullPackage().replace('.', File.separatorChar);
}
return path;
}
public RobotSpecification createRobotSpecification(RobotSpecification battleRobotSpec, String teamName) {
RobotSpecification specification;
if (battleRobotSpec != null) {
specification = battleRobotSpec;
} else {
specification = createRobotSpecification();
}
if (teamName != null) {
HiddenAccess.setTeamName(specification, teamName);
}
return specification;
}
public String toString() {
return itemUrl.toString();
}
}