/*
* Gate.java
*
* Copyright (c) 1995-2012, The University of Sheffield. See the file
* COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
*
* This file is part of GATE (see http://gate.ac.uk/), and is free
* software, licenced under the GNU Library General Public License,
* Version 2, June 1991 (in the distribution as file licence.html,
* and also available at http://gate.ac.uk/gate/licence.html).
*
* Hamish Cunningham, 31/07/98
*
* $Id: Gate.java 15646 2012-03-29 10:32:41Z valyt $
*/
package gate;
import gate.config.ConfigDataProcessor;
import gate.creole.CreoleRegisterImpl;
import gate.creole.ResourceData;
import gate.creole.metadata.CreoleResource;
import gate.event.CreoleListener;
import gate.gui.creole.manager.PluginUpdateManager;
import gate.util.Benchmark;
import gate.util.Files;
import gate.util.GateClassLoader;
import gate.util.GateException;
import gate.util.GateRuntimeException;
import gate.util.LuckyException;
import gate.util.OptionsMap;
import gate.util.Strings;
import gate.util.asm.AnnotationVisitor;
import gate.util.asm.ClassReader;
import gate.util.asm.ClassVisitor;
import gate.util.asm.Opcodes;
import gate.util.asm.Type;
import gate.util.asm.commons.EmptyVisitor;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import org.apache.log4j.Logger;
import org.jdom.Attribute;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
/**
* The class is responsible for initialising the GATE libraries, and providing
* access to singleton utility objects, such as the GATE class loader, CREOLE
* register and so on.
*/
public class Gate implements GateConstants {
/** A logger to use instead of sending messages to Out or Err **/
protected static final Logger log = Logger.getLogger(Gate.class);
/**
* The default StringBuffer size, it seems that we need longer string than the
* StringBuffer class default because of the high number of buffer expansions
*/
public static final int STRINGBUFFER_SIZE = 1024;
/**
* The default size to be used for Hashtable, HashMap and HashSet. The defualt
* is 11 and it leads to big memory usage. Having a default load factor of
* 0.75, table of size 4 can take 3 elements before being re-hashed - a values
* that seems to be optimal for most of the cases.
*/
public static final int HASH_STH_SIZE = 4;
/** The list of builtin URLs to search for CREOLE resources. */
private static String builtinCreoleDirectoryUrls[] = {
// "http://derwent.dcs.shef.ac.uk/gate.ac.uk/creole/"
// this has been moved to initCreoleRegister and made relative to
// the base URL returned by getUrl()
// "http://gate.ac.uk/creole/"
};
/** The GATE URI used to interpret custom GATE tags */
public static final String URI = "http://www.gate.ac.uk";
/** Minimum version of JDK we support */
protected static final String MIN_JDK_VERSION = "1.5";
/**
* Feature name that should be used to set if the benchmarking logging should
* be enabled or disabled.
*/
protected static final String ENABLE_BENCHMARKING_FEATURE_NAME =
"gate.enable.benchmark";
/** Is true if GATE is to be run in a sandbox **/
private static boolean sandboxed = false;
/**
* Find out if GATE is to be run in a sandbox or not. If true then
* GATE will not attempt to load any local configuration information during
* Initialisation making it possible to use GATE from within unsigned
* applets and web start applications.
* @return true if GATE is to be run in a sandbox, false otherwise
*/
public static boolean isSandboxed() {
return sandboxed;
}
/**
* Method to tell GATE if it is being run inside a JVM sandbox. If true then
* GATE will not attempt to load any local configuration information during
* Initialisation making it possible to use GATE from within unsigned
* applets and web start applications.
* @param sandboxed true if GATE is to be run in a sandbox, false otherwise
*/
public static void runInSandbox(boolean sandboxed) {
if (initFinished)
throw new IllegalStateException("Sandbox status cannot be changed after GATE has been initialised!");
Gate.sandboxed = sandboxed;
}
/** Get the minimum supported version of the JDK */
public static String getMinJdkVersion() {
return MIN_JDK_VERSION;
}
/**
* Initialisation - must be called by all clients before using any other parts
* of the library. Also initialises the CREOLE register and reads config data (<TT>gate.xml</TT>
* files).
*
* @see #initCreoleRegister
*/
public static void init() throws GateException {
// init local paths
if (!sandboxed) initLocalPaths();
// check if benchmarking should be enabled or disabled
if(System.getProperty(ENABLE_BENCHMARKING_FEATURE_NAME) != null
&& System.getProperty(ENABLE_BENCHMARKING_FEATURE_NAME).equalsIgnoreCase(
"true")) {
Benchmark.setBenchmarkingEnabled(true);
}
// builtin creole dir
if(builtinCreoleDir == null) {
String builtinCreoleDirPropertyValue =
System.getProperty(BUILTIN_CREOLE_DIR_PROPERTY_NAME);
if(builtinCreoleDirPropertyValue == null) {
// default to /gate/resources/creole in gate.jar
builtinCreoleDir = Files.getGateResource("/creole/");
}
else {
String builtinCreoleDirPath = builtinCreoleDirPropertyValue;
// add a slash onto the end of the path if it doesn't have one already -
// a creole directory URL should always end with a forward slash
if(!builtinCreoleDirPath.endsWith("/")) {
builtinCreoleDirPath += "/";
}
try {
builtinCreoleDir = new URL(builtinCreoleDirPath);
}
catch(MalformedURLException mue) {
// couldn't parse as a File either, so throw an exception
throw new GateRuntimeException(BUILTIN_CREOLE_DIR_PROPERTY_NAME
+ " value \"" + builtinCreoleDirPropertyValue + "\" could"
+ " not be parsed as either a URL or a file path.");
}
log.info("Using " + builtinCreoleDir + " as built-in CREOLE"
+ " directory URL");
}
}
// register the URL handler for the "gate://" URLs
System.setProperty("java.protocol.handler.pkgs", System
.getProperty("java.protocol.handler.pkgs")
+ "|" + "gate.util.protocols");
// initialise the symbols generator
lastSym = 0;
// create class loader and creole register if they're null
if(classLoader == null)
classLoader = new GateClassLoader("Top-Level GATE ClassLoader", Gate.class.getClassLoader());
if(creoleRegister == null) creoleRegister = new CreoleRegisterImpl();
if(knownPlugins == null) knownPlugins = new ArrayList<URL>();
if(autoloadPlugins == null) autoloadPlugins = new ArrayList<URL>();
if(pluginData == null) pluginData = new HashMap<URL, DirectoryInfo>();
// init the creole register
initCreoleRegister();
// init the data store register
initDataStoreRegister();
// read gate.xml files; this must come before creole register
// initialisation in order for the CREOLE-DIR elements to have and effect
if (!sandboxed) initConfigData();
if (!sandboxed) initCreoleRepositories();
// the creoleRegister acts as a proxy for datastore related events
dataStoreRegister.addCreoleListener(creoleRegister);
// some of the events are actually fired by the {@link gate.Factory}
Factory.addCreoleListener(creoleRegister);
// check we have a useable JDK
if(System.getProperty("java.version").compareTo(MIN_JDK_VERSION) < 0) { throw new GateException(
"GATE requires JDK " + MIN_JDK_VERSION + " or newer"); }
// register Lucene as a IR search engine
try {
registerIREngine("gate.creole.ir.lucene.LuceneIREngine");
}
catch(ClassNotFoundException cnfe) {
throw new GateRuntimeException(cnfe);
}
initFinished = true;
} // init()
/** Have we successfully run {@link #init()} before? */
public static boolean isInitialised() { return initFinished; }
/** Records initialisation status. */
protected static boolean initFinished = false;
/**
* Initialises the paths to local files of interest like the GATE home, the
* installed plugins home and site and user configuration files.
*/
protected static void initLocalPaths() {
// GATE Home
if(gateHome == null) {
String gateHomeStr = System.getProperty(GATE_HOME_PROPERTY_NAME);
if(gateHomeStr != null && gateHomeStr.length() > 0) {
gateHome = new File(gateHomeStr);
}
// if failed, try to guess
if(gateHome == null || !gateHome.exists()) {
log.warn("GATE home system property (\"" + GATE_HOME_PROPERTY_NAME
+ "\") not set.\nAttempting to guess...");
URL gateURL =
Thread.currentThread().getContextClassLoader().getResource(
"gate/Gate.class");
try {
if(gateURL.getProtocol().equals("jar")) {
// running from gate.jar
String gateURLStr = gateURL.getFile();
File gateJarFile =
new File(
new URI(gateURLStr.substring(0, gateURLStr.indexOf('!'))));
gateHome = gateJarFile.getParentFile().getParentFile();
}
else if(gateURL.getProtocol().equals("file")) {
// running from classes directory
File gateClassFile = Files.fileFromURL(gateURL);
gateHome =
gateClassFile.getParentFile().getParentFile().getParentFile();
}
log.warn("Using \"" + gateHome.getCanonicalPath()
+ "\" as GATE Home.\nIf this is not correct please set it manually"
+ " using the -D" + GATE_HOME_PROPERTY_NAME
+ " option in your start-up script");
}
catch(Throwable thr) {
throw new GateRuntimeException(
"Cannot guess GATE Home. Pease set it manually!", thr);
}
}
}
log.info("Using " + gateHome.toString() + " as GATE home");
// Plugins home
if(pluginsHome == null) {
String pluginsHomeStr = System.getProperty(PLUGINS_HOME_PROPERTY_NAME);
if(pluginsHomeStr != null && pluginsHomeStr.length() > 0) {
File homeFile = new File(pluginsHomeStr);
if(homeFile.exists() && homeFile.isDirectory()) {
pluginsHome = homeFile;
}
}
// if not set, use the GATE Home as a base directory
if(pluginsHome == null) {
File homeFile = new File(gateHome, PLUGINS);
if(homeFile.exists() && homeFile.isDirectory()) {
pluginsHome = homeFile;
}
}
// if still not set, throw exception
if(pluginsHome == null) { throw new GateRuntimeException(
"Could not infer installed plug-ins home!\n"
+ "Please set it manually using the -D" + PLUGINS_HOME_PROPERTY_NAME
+ " option in your start-up script."); }
}
log.info("Using " + pluginsHome.toString()
+ " as installed plug-ins directory.");
// site config
if(siteConfigFile == null) {
String siteConfigStr = System.getProperty(SITE_CONFIG_PROPERTY_NAME);
if(siteConfigStr != null && siteConfigStr.length() > 0) {
File configFile = new File(siteConfigStr);
if(configFile.exists()) siteConfigFile = configFile;
}
// if not set, use GATE home as base directory
if(siteConfigFile == null) {
File configFile = new File(gateHome, GATE_DOT_XML);
if(configFile.exists()) siteConfigFile = configFile;
}
// if still not set, throw exception
if(siteConfigFile == null) { throw new GateRuntimeException(
"Could not locate the site configuration file!\n"
+ "Please create it at "
+ new File(gateHome, GATE_DOT_XML).toString()
+ " or point to an existing one using the -D"
+ SITE_CONFIG_PROPERTY_NAME + " option in your start-up script!"); }
}
log.info("Using " + siteConfigFile.toString()
+ " as site configuration file.");
// user config
if(userConfigFile == null) {
String userConfigStr = System.getProperty(USER_CONFIG_PROPERTY_NAME);
if(userConfigStr != null && userConfigStr.length() > 0) {
userConfigFile = new File(userConfigStr);
} else {
userConfigFile = new File(getDefaultUserConfigFileName());
}
}
log.info("Using " + userConfigFile + " as user configuration file");
// user session
if(userSessionFile == null) {
String userSessionStr =
System.getProperty(GATE_USER_SESSION_PROPERTY_NAME);
if(userSessionStr != null && userSessionStr.length() > 0) {
userSessionFile = new File(userSessionStr);
}
else {
userSessionFile = new File(getDefaultUserSessionFileName());
}
}// if(userSessionFile == null)
log.info("Using " + userSessionFile + " as user session file");
}
/**
* Loads the CREOLE repositories (aka plugins) that the user has selected for
* automatic loading. Loads the information about known plugins in memory.
*/
protected static void initCreoleRepositories() {
// the logic is:
// get the list of know plugins from gate.xml
// add all the installed plugins
// get the list of loadable plugins
// load loadable plugins
// process the known plugins list
String knownPluginsPath =
(String)getUserConfig().get(KNOWN_PLUGIN_PATH_KEY);
if(knownPluginsPath != null && knownPluginsPath.length() > 0) {
StringTokenizer strTok =
new StringTokenizer(knownPluginsPath, ";", false);
while(strTok.hasMoreTokens()) {
String aKnownPluginPath = strTok.nextToken();
try {
URL aPluginURL = new URL(aKnownPluginPath);
addKnownPlugin(aPluginURL);
}
catch(MalformedURLException mue) {
log.error("Plugin error: " + aKnownPluginPath + " is an invalid URL!");
}
}
}
// add all the installed plugins
// pluginsHome is now set by initLocalPaths
// File pluginsHome = new File(System.getProperty(GATE_HOME_PROPERTY_NAME),
// "plugins");
File[] dirs = pluginsHome.listFiles();
for(int i = 0; i < dirs.length; i++) {
File creoleFile = new File(dirs[i], "creole.xml");
if(creoleFile.exists()) {
try {
URL pluginURL = dirs[i].toURI().toURL();
addKnownPlugin(pluginURL);
}
catch(MalformedURLException mue) {
// this should never happen
throw new GateRuntimeException(mue);
}
}
}
// register plugins installed in the user plugin directory
File userPluginsHome = PluginUpdateManager.getUserPluginsHome();
if (userPluginsHome != null && userPluginsHome.isDirectory()) {
for (File dir : userPluginsHome.listFiles()) {
File creoleFile = new File(dir, "creole.xml");
if(creoleFile.exists()) {
try {
URL pluginURL = dir.toURI().toURL();
addKnownPlugin(pluginURL);
}
catch(MalformedURLException mue) {
// this should never happen
throw new GateRuntimeException(mue);
}
}
}
}
// process the autoload plugins
String pluginPath = getUserConfig().getString(AUTOLOAD_PLUGIN_PATH_KEY);
// can be overridden by system property
String prop = System.getProperty(AUTOLOAD_PLUGIN_PATH_PROPERTY_NAME);
if(prop != null && prop.length() > 0) pluginPath = prop;
if(pluginPath == null || pluginPath.length() == 0) {
// no plugin to load stop here
return;
}
// load all loadable plugins
StringTokenizer strTok = new StringTokenizer(pluginPath, ";", false);
while(strTok.hasMoreTokens()) {
String aDir = strTok.nextToken();
try {
URL aPluginURL = new URL(aDir);
addAutoloadPlugin(aPluginURL);
}
catch(MalformedURLException mue) {
log.error("Cannot load " + aDir + " CREOLE repository.",mue);
}
try {
Iterator<URL> loadPluginsIter = getAutoloadPlugins().iterator();
while(loadPluginsIter.hasNext()) {
getCreoleRegister().registerDirectories(loadPluginsIter.next());
}
}
catch(GateException ge) {
log.error("Cannot load " + aDir + " CREOLE repository.",ge);
}
}
}
/** Initialise the CREOLE register. */
public static void initCreoleRegister() throws GateException {
// register the builtin CREOLE directories
for(int i = 0; i < builtinCreoleDirectoryUrls.length; i++)
try {
creoleRegister.addDirectory(new URL(builtinCreoleDirectoryUrls[i]));
}
catch(MalformedURLException e) {
throw new GateException(e);
}
/*
* We'll have to think about this. Right now it points to the creole inside
* the jar/classpath so it's the same as registerBuiltins
*/
// // add the GATE base URL creole directory
// creoleRegister.addDirectory(Gate.getUrl("creole/"));
// creoleRegister.registerDirectories();
// register the resources that are actually in gate.jar
creoleRegister.registerBuiltins();
} // initCreoleRegister
/** Initialise the DataStore register. */
public static void initDataStoreRegister() {
dataStoreRegister = new DataStoreRegister();
} // initDataStoreRegister()
/**
* Reads config data (<TT>gate.xml</TT> files). There are three sorts of
* these files:
* <UL>
* <LI> The builtin file from GATE's resources - this is read first.
* <LI> A site-wide init file given as a command-line argument or as a
* <TT>gate.config</TT> property - this is read second.
* <LI> The user's file from their home directory - this is read last.
* </UL>
* Settings from files read after some settings have already been made will
* simply overwrite the previous settings.
*/
public static void initConfigData() throws GateException {
ConfigDataProcessor configProcessor = new ConfigDataProcessor();
// parse the site configuration file
URL configURL;
try {
configURL = siteConfigFile.toURI().toURL();
}
catch(MalformedURLException mue) {
// this should never happen
throw new GateRuntimeException(mue);
}
try {
InputStream configStream = new FileInputStream(siteConfigFile);
configProcessor.parseConfigFile(configStream, configURL);
}
catch(IOException e) {
throw new GateException("Couldn't open site configuration file: "
+ configURL + " " + e);
}
// parse the user configuration data if present
if(userConfigFile != null && userConfigFile.exists()) {
try {
configURL = userConfigFile.toURI().toURL();
}
catch(MalformedURLException mue) {
// this should never happen
throw new GateRuntimeException(mue);
}
try {
InputStream configStream = new FileInputStream(userConfigFile);
configProcessor.parseConfigFile(configStream, configURL);
}
catch(IOException e) {
throw new GateException("Couldn't open user configuration file: "
+ configURL + " " + e);
}
}
// remember the init-time config options
originalUserConfig.putAll(userConfig);
log.debug("user config loaded; DBCONFIG="
+ DataStoreRegister.getConfigData());
} // initConfigData()
/**
* Attempts to guess the Unicode font for the platform.
*/
public static String guessUnicodeFont() {
// guess the Unicode font for the platform
String[] fontNames =
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
.getAvailableFontFamilyNames();
String unicodeFontName = null;
for(int i = 0; i < fontNames.length; i++) {
if(fontNames[i].equalsIgnoreCase("Arial Unicode MS")) {
unicodeFontName = fontNames[i];
break;
}
if(fontNames[i].toLowerCase().indexOf("unicode") != -1) {
unicodeFontName = fontNames[i];
}
}// for(int i = 0; i < fontNames.length; i++)
return unicodeFontName;
}
/**
* Get a URL that points to either an HTTP server or a file system that
* contains GATE files (such as test cases). The following locations are tried
* in sequence:
* <UL>
* <LI> <TT>http://derwent.dcs.shef.ac.uk/gate.ac.uk/</TT>, a
* Sheffield-internal development server (the gate.ac.uk affix is a copy of
* the file system present on GATE's main public server - see next item);
* <LI> <TT>http://gate.ac.uk/</TT>, GATE's main public server;
* <LI> <TT>http://localhost/gate.ac.uk/</TT>, a Web server running on the
* local machine;
* <LI> the local file system where the binaries for the current invocation of
* GATE are stored.
* </UL>
* In each case we assume that a Web server will be running on port 80, and
* that if we can open a socket to that port then the server is running. (This
* is a bit of a strong assumption, but this URL is used largely by the test
* suite, so we're not betting anything too critical on it.)
* <P>
* Note that the value returned will only be calculated when the existing
* value recorded by this class is null (which will be the case when neither
* setUrlBase nor getUrlBase have been called, or if setUrlBase(null) has been
* called).
*/
public static URL getUrl() throws GateException {
if(urlBase != null) return urlBase;
try {
// if we're assuming a net connection, try network servers
if(isNetConnected()) {
if(
// tryNetServer("gate-internal.dcs.shef.ac.uk", 80, "/") ||
// tryNetServer("derwent.dcs.shef.ac.uk", 80, "/gate.ac.uk/") ||
tryNetServer("gate.ac.uk", 80, "/")) {
log.debug("getUrl() returned " + urlBase);
return urlBase;
}
} // if isNetConnected() ...
// no network servers; try for a local host web server.
// we use InetAddress to get host name instead of using "localhost" coz
// badly configured Windoze IP sometimes doesn't resolve the latter
if(isLocalWebServer()
&& tryNetServer(InetAddress.getLocalHost().getHostName(), 80,
"/gate.ac.uk/")) {
log.debug("getUrlBase() returned " + urlBase);
return urlBase;
}
// try the local file system
tryFileSystem();
}
catch(MalformedURLException e) {
throw new GateException("Bad URL, getUrlBase(): " + urlBase + ": " + e);
}
catch(UnknownHostException e) {
throw new GateException("No host, getUrlBase(): " + urlBase + ": " + e);
}
// return value will be based on the file system, or null
log.debug("getUrlBase() returned " + urlBase);
return urlBase;
} // getUrl()
/**
* Get a URL that points to either an HTTP server or a file system that
* contains GATE files (such as test cases). Calls <TT>getUrl()</TT> then
* adds the <TT>path</TT> parameter to the result.
*
* @param path
* a path to add to the base URL.
* @see #getUrl()
*/
public static URL getUrl(String path) throws GateException {
getUrl();
if(urlBase == null) return null;
URL newUrl = null;
try {
newUrl = new URL(urlBase, path);
}
catch(MalformedURLException e) {
throw new GateException("Bad URL, getUrl( " + path + "): " + e);
}
log.debug("getUrl(" + path + ") returned " + newUrl);
return newUrl;
} // getUrl(path)
/**
* Flag controlling whether we should try to access the net, e.g. when setting
* up a base URL.
*/
private static boolean netConnected = false;
private static int lastSym;
/**
* A list of names of classes that implement {@link gate.creole.ir.IREngine}
* that will be used as information retrieval engines.
*/
private static Set<String> registeredIREngines = new HashSet<String>();
/**
* Registers a new IR engine. The class named should implement
* {@link gate.creole.ir.IREngine} and be accessible via the GATE class
* loader.
*
* @param className
* the fully qualified name of the class to be registered
* @throws GateException
* if the class does not implement the
* {@link gate.creole.ir.IREngine} interface.
* @throws ClassNotFoundException
* if the named class cannot be found.
*/
public static void registerIREngine(String className) throws GateException,
ClassNotFoundException {
Class<?> aClass = Class.forName(className, true, Gate.getClassLoader());
if(gate.creole.ir.IREngine.class.isAssignableFrom(aClass)) {
registeredIREngines.add(className);
}
else {
throw new GateException(className + " does not implement the "
+ gate.creole.ir.IREngine.class.getName() + " interface!");
}
}
/**
* Unregisters a previously registered IR engine.
*
* @param className
* the name of the class to be removed from the list of registered IR
* engines.
* @return true if the class was found and removed.
*/
public static boolean unregisterIREngine(String className) {
return registeredIREngines.remove(className);
}
/**
* Gets the set of registered IR engines.
*
* @return an unmodifiable {@link java.util.Set} value.
*/
public static Set<String> getRegisteredIREngines() {
return Collections.unmodifiableSet(registeredIREngines);
}
/**
* Gets the GATE home location.
*
* @return a File value.
*/
public static File getGateHome() {
return gateHome;
}
/** Should we assume we're connected to the net? */
public static boolean isNetConnected() {
return netConnected;
}
/**
* Tell GATE whether to assume we're connected to the net. Has to be called
* <B>before</B> {@link #init()}.
*/
public static void setNetConnected(boolean b) {
netConnected = b;
}
/**
* Flag controlling whether we should try to access a web server on localhost,
* e.g. when setting up a base URL. Has to be called <B>before</B>
* {@link #init()}.
*/
private static boolean localWebServer = false;
/** Should we assume there's a local web server? */
public static boolean isLocalWebServer() {
return localWebServer;
}
/** Tell GATE whether to assume there's a local web server. */
public static void setLocalWebServer(boolean b) {
localWebServer = b;
}
/**
* Try to contact a network server. When sucessfull sets urlBase to an HTTP
* URL for the server.
*
* @param hostName
* the name of the host to try and connect to
* @param serverPort
* the port to try and connect to
* @param path
* a path to append to the URL when we make a successfull connection.
* E.g. for host xyz, port 80, path /thing, the resultant URL would
* be <TT>http://xyz:80/thing</TT>.
*/
public static boolean tryNetServer(String hostName, int serverPort,
String path) throws MalformedURLException {
log.debug("tryNetServer(hostName=" + hostName + ", serverPort="
+ serverPort + ", path=" + path + ")");
// is the host listening at the port?
try {
URL url = new URL("http://" + hostName + ":" + serverPort + "/");
URLConnection uConn = url.openConnection();
HttpURLConnection huConn = null;
if(uConn instanceof HttpURLConnection) huConn = (HttpURLConnection)uConn;
if(huConn.getResponseCode() == -1) return false;
}
catch(IOException e) {
return false;
}
// if(socket != null) {
urlBase = new URL("http", hostName, serverPort, path);
return true;
// }
// return false;
} // tryNetServer()
/** Try to find GATE files in the local file system */
protected static boolean tryFileSystem() throws MalformedURLException {
String urlBaseName = locateGateFiles();
log.debug("tryFileSystem: " + urlBaseName);
urlBase = new URL(urlBaseName + "gate/resources/gate.ac.uk/");
return urlBase == null;
} // tryFileSystem()
/**
* Find the location of the GATE binaries (and resources) in the local file
* system.
*/
public static String locateGateFiles() {
String aGateResourceName = "gate/resources/creole/creole.xml";
URL resourcesUrl = Gate.getClassLoader().getResource(aGateResourceName);
StringBuffer basePath = new StringBuffer(resourcesUrl.toExternalForm());
String urlBaseName =
basePath.substring(0, basePath.length() - aGateResourceName.length());
return urlBaseName;
} // locateGateFiles
/**
* Checks whether a particular class is a Gate defined type
*/
public static boolean isGateType(String classname) {
boolean res = getCreoleRegister().containsKey(classname);
if(!res) {
try {
Class<?> aClass = Class.forName(classname, true, Gate.getClassLoader());
res =
Resource.class.isAssignableFrom(aClass);
}
catch(ClassNotFoundException cnfe) {
return false;
}
}
return res;
}
/** Returns the value for the HIDDEN attribute of a feature map */
static public boolean getHiddenAttribute(FeatureMap fm) {
if(fm == null) return false;
Object value = fm.get(HIDDEN_FEATURE_KEY);
return value != null && value instanceof String
&& ((String)value).equals("true");
}
/** Sets the value for the HIDDEN attribute of a feature map */
static public void setHiddenAttribute(FeatureMap fm, boolean hidden) {
if(hidden) {
fm.put(HIDDEN_FEATURE_KEY, "true");
}
else {
fm.remove(HIDDEN_FEATURE_KEY);
}
}
/**
* Registers a {@link gate.event.CreoleListener} with the Gate system
*/
public static synchronized void addCreoleListener(CreoleListener l) {
creoleRegister.addCreoleListener(l);
} // addCreoleListener
/** Set the URL base for GATE files, e.g. <TT>http://gate.ac.uk/</TT>. */
public static void setUrlBase(URL urlBase) {
Gate.urlBase = urlBase;
}
/** The URL base for GATE files, e.g. <TT>http://gate.ac.uk/</TT>. */
private static URL urlBase = null;
/**
* Class loader used e.g. for loading CREOLE modules, of compiling JAPE rule
* RHSs.
*/
private static GateClassLoader classLoader = null;
/** Get the GATE class loader. */
public static GateClassLoader getClassLoader() {
return classLoader;
}
/** The CREOLE register. */
private static CreoleRegister creoleRegister = null;
/** Get the CREOLE register. */
public static CreoleRegister getCreoleRegister() {
return creoleRegister;
}
/** The DataStore register */
private static DataStoreRegister dataStoreRegister = null;
/**
* The current executable under execution.
*/
private static gate.Executable currentExecutable;
/** Get the DataStore register. */
public static DataStoreRegister getDataStoreRegister() {
return dataStoreRegister;
} // getDataStoreRegister
/**
* Sets the {@link Executable} currently under execution. At a given time
* there can be only one executable set. After the executable has finished its
* execution this value should be set back to null. An attempt to set the
* executable while this value is not null will result in the method call
* waiting until the old executable is set to null.
*/
public synchronized static void setExecutable(gate.Executable executable) {
if(executable == null)
currentExecutable = executable;
else {
while(getExecutable() != null) {
try {
Thread.sleep(200);
}
catch(InterruptedException ie) {
throw new LuckyException(ie.toString());
}
}
currentExecutable = executable;
}
} // setExecutable
/**
* Returns the curently set executable.
*
* @see #setExecutable(gate.Executable)
*/
public synchronized static gate.Executable getExecutable() {
return currentExecutable;
} // getExecutable
/**
* Returns a new unique string
*/
public synchronized static String genSym() {
StringBuffer buff =
new StringBuffer(Integer.toHexString(lastSym++).toUpperCase());
for(int i = buff.length(); i <= 4; i++)
buff.insert(0, '0');
return buff.toString();
} // genSym
/** GATE development environment configuration data (stored in gate.xml). */
private static OptionsMap userConfig = new OptionsMap();
/**
* This map stores the init-time config data in case we need it later. GATE
* development environment configuration data (stored in gate.xml).
*/
private static OptionsMap originalUserConfig = new OptionsMap();
/** Name of the XML element for GATE development environment config data. */
private static String userConfigElement = "GATECONFIG";
/**
* Gate the name of the XML element for GATE development environment config
* data.
*/
public static String getUserConfigElement() {
return userConfigElement;
}
/**
* Get the site config file (generally set during command-line processing or
* as a <TT>gate.config</TT> property). If the config is null, this method
* checks the <TT>gate.config</TT> property and uses it if non-null.
*/
public static File getSiteConfigFile() {
if(siteConfigFile == null) {
String gateConfigProperty = System.getProperty(GATE_CONFIG_PROPERTY);
if(gateConfigProperty != null)
siteConfigFile = new File(gateConfigProperty);
}
return siteConfigFile;
} // getSiteConfigFile
/** Set the site config file (e.g. during command-line processing). */
public static void setSiteConfigFile(File siteConfigFile) {
Gate.siteConfigFile = siteConfigFile;
} // setSiteConfigFile
/** Shorthand for local newline */
private static String nl = Strings.getNl();
/** An empty config data file. */
private static String emptyConfigFile =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + nl + "<!-- " + GATE_DOT_XML
+ ": GATE configuration data -->" + nl + "<GATE>" + nl + "" + nl
+ "<!-- NOTE: the next element may be overwritten by the GUI!!! -->" + nl
+ "<" + userConfigElement + "/>" + nl + "" + nl + "</GATE>" + nl;
/**
* Get an empty config file. <B>NOTE:</B> this method is intended only for
* use by the test suite.
*/
public static String getEmptyConfigFile() {
return emptyConfigFile;
}
/**
* Get the GATE development environment configuration data (initialised from
* <TT>gate.xml</TT>).
*/
public static OptionsMap getUserConfig() {
return userConfig;
}
/**
* Get the original, initialisation-time, GATE development environment
* configuration data (initialised from <TT>gate.xml</TT>).
*/
public static OptionsMap getOriginalUserConfig() {
return originalUserConfig;
} // getOriginalUserConfig
/**
* Update the GATE development environment configuration data in the user's
* <TT>gate.xml</TT> file (create one if it doesn't exist).
*/
public static void writeUserConfig() throws GateException {
//if we are running in a sandbox then don't try and write anything
if (sandboxed) return;
String pluginsHomeStr;
try {
pluginsHomeStr = pluginsHome.getCanonicalPath();
}
catch(IOException ioe) {
throw new GateRuntimeException(
"Problem while locating the plug-ins home!", ioe);
}
String userPluginHomeStr;
try {
File userPluginHome = PluginUpdateManager.getUserPluginsHome();
userPluginHomeStr = (userPluginHome != null ? userPluginHome.getCanonicalPath() : null);
}
catch (IOException ioe) {
throw new GateRuntimeException("Unable to access user plugin directory!", ioe);
}
// update the values for knownPluginPath
String knownPluginPath = "";
Iterator<URL> pluginIter = getKnownPlugins().iterator();
while(pluginIter.hasNext()) {
URL aPluginURL = pluginIter.next();
// do not save installed plug-ins - they get loaded automatically
if(aPluginURL.getProtocol().equals("file")) {
File pluginDirectory = Files.fileFromURL(aPluginURL);
try {
if(pluginDirectory.getCanonicalPath().startsWith(pluginsHomeStr))
continue;
if (userPluginHomeStr != null && pluginDirectory.getCanonicalPath().startsWith(userPluginHomeStr))
continue;
}
catch(IOException ioe) {
throw new GateRuntimeException("Problem while locating the plug-in"
+ aPluginURL.toString(), ioe);
}
}
if(knownPluginPath.length() > 0) knownPluginPath += ";";
knownPluginPath += aPluginURL.toExternalForm();
}
getUserConfig().put(KNOWN_PLUGIN_PATH_KEY, knownPluginPath);
// update the autoload plugin list
String loadPluginPath = "";
pluginIter = getAutoloadPlugins().iterator();
while(pluginIter.hasNext()) {
URL aPluginURL = pluginIter.next();
if(loadPluginPath.length() > 0) loadPluginPath += ";";
loadPluginPath += aPluginURL.toExternalForm();
}
getUserConfig().put(AUTOLOAD_PLUGIN_PATH_KEY, loadPluginPath);
// the user's config file
// String configFileName = getUserConfigFileName();
// File configFile = new File(configFileName);
File configFile = getUserConfigFile();
// create if not there, then update
try {
// if the file doesn't exist, create one with an empty GATECONFIG
if(!configFile.exists()) {
FileOutputStream fos = new FileOutputStream(configFile);
OutputStreamWriter writer = new OutputStreamWriter(fos, "UTF-8");
writer.write(emptyConfigFile);
writer.close();
}
// update the config element of the file
Files.updateXmlElement(configFile, userConfigElement, userConfig);
}
catch(IOException e) {
throw new GateException("problem writing user " + GATE_DOT_XML + ": "
+ nl + e.toString());
}
} // writeUserConfig
/**
* Get the name of the user's <TT>gate.xml</TT> config file (this doesn't
* guarantee that file exists!).
*
* @deprecated Use {@link #getUserConfigFile} instead.
*/
public static String getUserConfigFileName() {
return getDefaultUserConfigFileName();
} // getUserConfigFileName
/**
* Get the default path to the user's config file, which is used unless an
* alternative name has been specified via system properties or
* {@link #setUserConfigFile}.
*
* @return the default user config file path.
*/
public static String getDefaultUserConfigFileName() {
String filePrefix = "";
if(runningOnUnix()) filePrefix = ".";
String userConfigName =
System.getProperty("user.home") + Strings.getFileSep() + filePrefix
+ GATE_DOT_XML;
return userConfigName;
} // getDefaultUserConfigFileName
/**
* Get the default path to the user's session file, which is used unless an
* alternative name has been specified via system properties or
* {@link #setUserSessionFile(File)}
*
* @return the default user session file path.
*/
public static String getDefaultUserSessionFileName() {
String filePrefix = "";
if(runningOnUnix()) filePrefix = ".";
String userSessionName =
System.getProperty("user.home") + Strings.getFileSep() + filePrefix
+ GATE_DOT_SER;
return userSessionName;
} // getUserSessionFileName
/**
* This method tries to guess if we are on a UNIX system. It does this by
* checking the value of <TT>System.getProperty("file.separator")</TT>; if
* this is "/" it concludes we are on UNIX. <B>This is obviously not a very
* good idea in the general case, so nothing much should be made to depend on
* this method (e.g. just naming of config file <TT>.gate.xml</TT> as
* opposed to <TT>gate.xml</TT>)</B>.
*/
public static boolean runningOnUnix() {
return Strings.getFileSep().equals("/");
} // runningOnUnix
/**
* This method tries to guess if we are on a Mac OS X system. It does this
* by checking the value of <TT>System.getProperty("os.name")</TT>. Note
* that if this method returns true, {@link #runningOnUnix()} will also
* return true (i.e. Mac is considered a Unix platform) but the reverse is
* not necessarily the case.
*/
public static boolean runningOnMac() {
return System.getProperty("os.name").toLowerCase().startsWith("mac os x");
}
/**
* Returns the list of CREOLE directories the system knows about (either
* pre-installed plugins in the plugins directory or CREOLE directories that
* have previously been loaded manually).
*
* @return a {@link List} of {@link URL}s.
*/
public static List<URL> getKnownPlugins() {
return knownPlugins;
}
/**
* Adds the plugin to the list of known plugins.
*
* @param pluginURL
* the URL for the new plugin.
*/
public static void addKnownPlugin(URL pluginURL) {
pluginURL = normaliseCreoleUrl(pluginURL);
if(knownPlugins.contains(pluginURL)) return;
knownPlugins.add(pluginURL);
}
/**
* Makes sure the provided URL ends with "/" (CREOLE URLs always point to
* directories so thry should always end with a slash.
*
* @param url
* the URL to be normalised
* @return the (maybe) corrected URL.
*/
public static URL normaliseCreoleUrl(URL url) {
// CREOLE URLs are directory URLs so they should end with "/"
String urlName = url.toExternalForm();
String separator = "/";
if(urlName.endsWith(separator)) {
return url;
}
else {
urlName += separator;
try {
return new URL(urlName);
}
catch(MalformedURLException mue) {
throw new GateRuntimeException(mue);
}
}
}
/**
* Returns the list of CREOLE directories the system loads automatically at
* start-up.
*
* @return a {@link List} of {@link URL}s.
*/
public static List<URL> getAutoloadPlugins() {
return autoloadPlugins;
}
/**
* Adds a new directory to the list of plugins that are loaded automatically
* at start-up.
*
* @param pluginUrl
* the URL for the new plugin.
*/
public static void addAutoloadPlugin(URL pluginUrl) {
pluginUrl = normaliseCreoleUrl(pluginUrl);
if(autoloadPlugins.contains(pluginUrl)) return;
// make sure it's known
addKnownPlugin(pluginUrl);
// add it to autoload list
autoloadPlugins.add(pluginUrl);
}
/**
* Gets the information about a known directory.
*
* @param directory
* the URL for the directory in question.
* @return a {@link DirectoryInfo} value.
*/
public static DirectoryInfo getDirectoryInfo(URL directory) {
directory = normaliseCreoleUrl(directory);
if(!knownPlugins.contains(directory)) return null;
DirectoryInfo dInfo = pluginData.get(directory);
if(dInfo == null) {
dInfo = new DirectoryInfo(directory);
pluginData.put(directory, dInfo);
}
return dInfo;
}
/**
* Returns information about plugin directories which provide the requested
* resource
*
* @param resourceClassName
* the class name of the resource you are interested in
* @return information about the directories which provide an implementation
* of the requested resource
*/
public static Set<DirectoryInfo> getDirectoryInfo(String resourceClassName) {
Set<DirectoryInfo> dirs = new HashSet<DirectoryInfo>();
for (URL url : knownPlugins) {
DirectoryInfo dInfo = getDirectoryInfo(url);
for (ResourceInfo rInfo : dInfo.getResourceInfoList()) {
if (rInfo.resourceClassName.equals(resourceClassName)) {
dirs.add(dInfo);
}
}
}
return dirs;
}
/**
* Tells the system to "forget" about one previously known
* directory. If the specified directory was loaded, it will be unloaded as
* well - i.e. all the metadata relating to resources defined by this
* directory will be removed from memory.
*
* @param pluginURL
*/
public static void removeKnownPlugin(URL pluginURL) {
pluginURL = normaliseCreoleUrl(pluginURL);
knownPlugins.remove(pluginURL);
autoloadPlugins.remove(pluginURL);
creoleRegister.removeDirectory(pluginURL);
pluginData.remove(pluginURL);
}
/**
* Tells the system to remove a plugin URL from the list of plugins that are
* loaded automatically at system start-up. This will be reflected in the
* user's configuration data file.
*
* @param pluginURL
* the URL to be removed.
*/
public static void removeAutoloadPlugin(URL pluginURL) {
pluginURL = normaliseCreoleUrl(pluginURL);
autoloadPlugins.remove(pluginURL);
}
/**
* Stores information about the contents of a CREOLE directory.
*/
public static class DirectoryInfo {
private String name, html;
private boolean core, remote;
public boolean isCorePlugin() {
return core;
}
public boolean isRemotePlugin() {
return remote;
}
public boolean isUserPlugin() {
File userPluginsHome = PluginUpdateManager.getUserPluginsHome();
return (userPluginsHome != null
&& getUrl().toString()
.startsWith(userPluginsHome.toURI().toString()));
}
public String toHTMLString() {
return html;
}
public DirectoryInfo(URL url) {
this.url = normaliseCreoleUrl(url);
valid = true;
resourceInfoList = new ArrayList<ResourceInfo>();
// this may invalidate it if something goes wrong
parseCreole();
remote = !this.url.getProtocol().equalsIgnoreCase("file");
if (Gate.isSandboxed() || Gate.getPluginsHome() == null) {
core = false;
}
else {
core = !remote && (url.toString().startsWith(Gate.getPluginsHome().toURI().toString()));
}
html =
"<html><body>"
+ getName()
+ "<br><span style='font-size: 80%;'>"
+ (remote ? this.url.toString() : Files.fileFromURL(
this.url).getAbsolutePath())
+ "</span></body></html>";
}
public String getName() {
if(name != null) return name;
// url.getPath() works for jar URLs; url.toURI().getPath() doesn't
// because jars aren't considered "hierarchical"
name = url.getPath();
if(name.endsWith("/")) {
name = name.substring(0, name.length() - 1);
}
int lastSlash = name.lastIndexOf("/");
if(lastSlash != -1) {
name = name.substring(lastSlash + 1);
}
try {
// convert to (relative) URI and extract path. This will
// decode any %20 escapes in the name.
name = new URI(name).getPath();
} catch(URISyntaxException ex) {
// ignore, this should have been checked when adding the URL!
}
return name;
}
/**
* Performs a shallow parse of the creole.xml file to get the information
* about the resources contained.
*/
protected void parseCreole() {
SAXBuilder builder = new SAXBuilder(false);
try {
URL creoleFileURL = new URL(url, "creole.xml");
org.jdom.Document creoleDoc = builder.build(creoleFileURL);
final Map<String, ResourceInfo> resInfos = new LinkedHashMap<String, ResourceInfo>();
List<Element> jobsList = new ArrayList<Element>();
List<String> jarsToScan = new ArrayList<String>();
List<String> allJars = new ArrayList<String>();
jobsList.add(creoleDoc.getRootElement());
while(!jobsList.isEmpty()) {
Element currentElem = jobsList.remove(0);
if(currentElem.getName().equalsIgnoreCase("JAR")) {
List<Attribute> attrs = currentElem.getAttributes();
Iterator<Attribute> attrsIt = attrs.iterator();
while(attrsIt.hasNext()) {
Attribute attr = attrsIt.next();
if(attr.getName().equalsIgnoreCase("SCAN") && attr.getBooleanValue()) {
jarsToScan.add(currentElem.getTextTrim());
break;
}
}
allJars.add(currentElem.getTextTrim());
}
else if(currentElem.getName().equalsIgnoreCase("RESOURCE")) {
// we don't go deeper than resources so no recursion here
String resName = currentElem.getChildTextTrim("NAME");
String resClass = currentElem.getChildTextTrim("CLASS");
String resComment = currentElem.getChildTextTrim("COMMENT");
if(!resInfos.containsKey(resClass)) {
// create the handler
ResourceInfo rHandler =
new ResourceInfo(resName, resClass, resComment);
resInfos.put(resClass, rHandler);
}
}
else {
// this is some higher level element -> simulate recursion
// we want Depth-first-search so we need to add at the beginning
List<Element> newJobsList = new ArrayList<Element>(currentElem.getChildren());
newJobsList.addAll(jobsList);
jobsList = newJobsList;
}
}
// now process the jar files with SCAN="true", looking for any extra
// CreoleResource annotated classes.
for(String jarFile : jarsToScan) {
URL jarUrl = new URL(url, jarFile);
scanJar(jarUrl, resInfos);
}
// see whether any of the ResourceInfo objects are still incomplete
// (don't have a name)
List<ResourceInfo> incompleteResInfos = new ArrayList<ResourceInfo>();
for(ResourceInfo ri : resInfos.values()) {
if(ri.getResourceName() == null) {
incompleteResInfos.add(ri);
}
}
if(!incompleteResInfos.isEmpty()) {
fillInResInfos(incompleteResInfos, allJars);
}
// if any of the resource infos still don't have a name, take it from
// the class name.
for(ResourceInfo ri : incompleteResInfos) {
if(ri.getResourceName() == null) {
ri.resourceName = ri.resourceClassName.substring(
ri.resourceClassName.lastIndexOf('.') + 1);
}
}
// finally, we have the complete list of ResourceInfos
resourceInfoList.addAll(resInfos.values());
}
catch(IOException ioe) {
valid = false;
log.error("Problem while parsing plugin " + url.toExternalForm() + "!\n"
+ ioe.toString() + "\nPlugin not available!");
}
catch(JDOMException jde) {
valid = false;
log.error("Problem while parsing plugin " + url.toExternalForm() + "!\n"
+ jde.toString() + "\nPlugin not available!");
}
}
protected void scanJar(URL jarUrl, Map<String, ResourceInfo> resInfos) throws IOException {
JarInputStream jarInput = new JarInputStream(jarUrl.openStream(), false);
JarEntry entry = null;
while((entry = jarInput.getNextJarEntry()) != null) {
String entryName = entry.getName();
if(entryName != null && entryName.endsWith(".class")) {
final String className = entryName.substring(0,
entryName.length() - 6).replace('/', '.');
if(!resInfos.containsKey(className)) {
ClassReader classReader = new ClassReader(jarInput);
ResourceInfo resInfo = new ResourceInfo(null, className, null);
ResourceInfoVisitor visitor = new ResourceInfoVisitor(resInfo);
classReader.accept(visitor, ClassReader.SKIP_CODE |
ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
if(visitor.isCreoleResource()) {
resInfos.put(className, resInfo);
}
}
}
}
jarInput.close();
}
protected void fillInResInfos(List<ResourceInfo> incompleteResInfos,
List<String> allJars) throws IOException {
// now create a temporary class loader with all the JARs (scanned or
// not), so we can look up all the referenced classes in the normal
// way and read their CreoleResource annotations (if any).
URL[] jarUrls = new URL[allJars.size()];
for(int i = 0; i < jarUrls.length; i++) {
jarUrls[i] = new URL(url, allJars.get(i));
}
ClassLoader tempClassLoader = new URLClassLoader(jarUrls,
Gate.class.getClassLoader());
for(ResourceInfo ri : incompleteResInfos) {
String classFile = ri.getResourceClassName().replace('.', '/')
+ ".class";
InputStream classStream = tempClassLoader.getResourceAsStream(classFile);
if(classStream != null) {
ClassReader classReader = new ClassReader(classStream);
ClassVisitor visitor = new ResourceInfoVisitor(ri);
classReader.accept(visitor, ClassReader.SKIP_CODE |
ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
classStream.close();
}
}
}
/**
* @return Returns the resourceInfoList.
*/
public List<ResourceInfo> getResourceInfoList() {
return resourceInfoList;
}
/**
* @return Returns the url.
*/
public URL getUrl() {
return url;
}
/**
* @return Returns the valid.
*/
public boolean isValid() {
return valid;
}
/**
* The URL for the CREOLE directory.
*/
protected URL url;
/**
* Is the directory valid (i.e. is the location reachable and the creole.xml
* file parsable).
*/
protected boolean valid;
/**
* The list of {@link Gate.ResourceInfo} objects.
*/
protected List<ResourceInfo> resourceInfoList;
}
/**
* Stores information about a resource defined by a CREOLE directory. The
* resource might not have been loaded in the system so not all information
* normally provided by the {@link ResourceData} class is available. This is
* what makes this class different from {@link ResourceData}.
*/
public static class ResourceInfo {
public ResourceInfo(String name, String className, String comment) {
this.resourceClassName = className;
this.resourceName = name;
this.resourceComment = comment;
}
/**
* @return Returns the resourceClassName.
*/
public String getResourceClassName() {
return resourceClassName;
}
/**
* @return Returns the resourceComment.
*/
public String getResourceComment() {
return resourceComment;
}
/**
* @return Returns the resourceName.
*/
public String getResourceName() {
return resourceName;
}
/**
* The class for the resource.
*/
protected String resourceClassName;
/**
* The resource name.
*/
protected String resourceName;
/**
* The comment for the resource.
*/
protected String resourceComment;
}
/**
* ClassVisitor that uses information from a CreoleResource annotation on the
* visited class (if such exists) to fill in the name and comment in the
* corresponding ResourceInfo.
*/
private static class ResourceInfoVisitor extends EmptyVisitor {
private ResourceInfo resInfo;
private boolean foundCreoleResource = false;
private boolean isAbstract = false;
public ResourceInfoVisitor(ResourceInfo resInfo) {
this.resInfo = resInfo;
}
public boolean isCreoleResource() {
return foundCreoleResource && !isAbstract;
}
/**
* Type descriptor for the CreoleResource annotation type.
*/
private static final String CREOLE_RESOURCE_DESC =
Type.getDescriptor(CreoleResource.class);
/**
* Visit the class header, checking whether this is an abstract class or
* interface and setting the isAbstract flag appropriately.
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
isAbstract = ((access &
(Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)) != 0);
}
/**
* Visit an annotation on the class.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
// we've found a CreoleResource annotation on this class
if(desc.equals(CREOLE_RESOURCE_DESC)) {
foundCreoleResource = true;
return new EmptyVisitor() {
public void visit(String name, Object value) {
if(name.equals("name") && resInfo.resourceName == null) {
resInfo.resourceName = (String)value;
}
else if(name.equals("comment") && resInfo.resourceComment == null) {
resInfo.resourceComment = (String)value;
}
}
public AnnotationVisitor visitAnnotation(String name,
String desc) {
// don't want to recurse into AutoInstance annotations
return new EmptyVisitor();
}
};
}
else {
return super.visitAnnotation(desc, visible);
}
}
}
/**
* The top level directory of the GATE installation.
*/
protected static File gateHome;
/** Site config file */
private static File siteConfigFile;
/** User config file */
private static File userConfigFile;
/**
* The top level directory for GATE installed plugins.
*/
protected static File pluginsHome;
/**
* The "builtin" creole directory URL, where the creole.xml that defines
* things like DocumentImpl can be found.
*/
protected static URL builtinCreoleDir;
/**
* The user session file to use.
*/
protected static File userSessionFile;
/**
* Set the location of the GATE home directory.
*
* @throws IllegalStateException
* if the value has already been set.
*/
public static void setGateHome(File gateHome) {
if(Gate.gateHome != null) { throw new IllegalStateException(
"gateHome has already been set"); }
Gate.gateHome = gateHome;
}
/**
* Set the location of the plugins directory.
*
* @throws IllegalStateException
* if the value has already been set.
*/
public static void setPluginsHome(File pluginsHome) {
if(Gate.pluginsHome != null) { throw new IllegalStateException(
"pluginsHome has already been set"); }
Gate.pluginsHome = pluginsHome;
}
/**
* Get the location of the plugins directory.
*
* @return the plugins drectory, or null if this has not yet been set (i.e.
* <code>Gate.init()</code> has not yet been called).
*/
public static File getPluginsHome() {
return pluginsHome;
}
/**
* Set the location of the user's config file.
*
* @throws IllegalStateException
* if the value has already been set.
*/
public static void setUserConfigFile(File userConfigFile) {
if(Gate.userConfigFile != null) { throw new IllegalStateException(
"userConfigFile has already been set"); }
Gate.userConfigFile = userConfigFile;
}
/**
* Get the location of the user's config file.
*
* @return the user config file, or null if this has not yet been set (i.e.
* <code>Gate.init()</code> has not yet been called).
*/
public static File getUserConfigFile() {
return userConfigFile;
}
/**
* Set the URL to the "builtin" creole directory. The URL must point to a
* directory, and must end with a forward slash.
*
* @throws IllegalStateException
* if the value has already been set.
*/
public static void setBuiltinCreoleDir(URL builtinCreoleDir) {
if(Gate.builtinCreoleDir != null) { throw new IllegalStateException(
"builtinCreoleDir has already been set"); }
Gate.builtinCreoleDir = builtinCreoleDir;
}
/**
* Get the URL to the "builtin" creole directory, i.e. the directory that
* contains the creole.xml file that defines things like DocumentImpl, the
* Controllers, etc.
*/
public static URL getBuiltinCreoleDir() {
return builtinCreoleDir;
}
/**
* Set the user session file. This can only done prior to calling Gate.init()
* which will set the file to either the OS-specific default or whatever has
* been set by the property gate.user.session
*
* @throws IllegalStateException
* if the value has already been set.
*/
public static void setUserSessionFile(File newUserSessionFile) {
if(Gate.userSessionFile != null) { throw new IllegalStateException(
"userSessionFile has already been set"); }
Gate.userSessionFile = newUserSessionFile;
}
/**
* Get the user session file.
*
* @return the file corresponding to the user session file or null, if not yet
* set.
*/
public static File getUserSessionFile() {
return userSessionFile;
}
/**
* The list of plugins (aka CREOLE directories) the system knows about. This
* list contains URL objects.
*/
private static List<URL> knownPlugins;
/**
* The list of plugins (aka CREOLE directories) the system loads automatically
* at start-up. This list contains URL objects.
*/
protected static List<URL> autoloadPlugins;
/**
* Map from URL of directory to {@link DirectoryInfo}.
*/
protected static Map<URL, DirectoryInfo> pluginData;
/**
* Flag for whether to use native serialization or xml serialization when
* saving applications.
*/
private static boolean useXMLSerialization = true;
/**
* Tell GATE whether to use XML serialization for applications.
*/
public static void setUseXMLSerialization(boolean useXMLSerialization) {
Gate.useXMLSerialization = useXMLSerialization;
}
/**
* Should we use XML serialization for applications.
*/
public static boolean getUseXMLSerialization() {
return useXMLSerialization;
}
/**
* Returns the listeners map, a map that holds all the listeners that
* are singletons (e.g. the status listener that updates the status
* bar on the main frame or the progress listener that updates the
* progress bar on the main frame). The keys used are the class names
* of the listener interface and the values are the actual listeners
* (e.g "gate.event.StatusListener" -> this). The returned map is the
* actual data member used to store the listeners so any changes in
* this map will be visible to everyone.
* @return the listeners map
*/
public static java.util.Map<String, EventListener> getListeners() {
return listeners;
}
/**
* A Map which holds listeners that are singletons (e.g. the status
* listener that updates the status bar on the main frame or the
* progress listener that updates the progress bar on the main frame).
* The keys used are the class names of the listener interface and the
* values are the actual listeners (e.g "gate.event.StatusListener" ->
* this).
*/
private static final java.util.Map<String, EventListener> listeners =
new HashMap<String, EventListener>();
} // class Gate