org.gjt.sp.jedit.ServiceManager Maven / Gradle / Ivy
/*
* ServiceManager.java - Handles services.xml files in plugins
* :tabSize=8:indentSize=8:noTabs=false:
* :folding=explicit:collapseFolds=1:
*
* Copyright (C) 2003 Slava Pestov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.gjt.sp.jedit;
import java.io.*;
import java.net.URL;
import java.util.*;
import org.gjt.sp.util.Log;
import org.gjt.sp.util.XMLUtilities;
import org.gjt.sp.util.StandardUtilities;
import org.gjt.sp.jedit.buffer.FoldHandlerProvider;
import org.gjt.sp.jedit.buffer.FoldHandler;
/**
* A generic way for plugins to provide various API extensions.
*
* Services are loaded from files named services.xml
inside the
* plugin JAR. A service definition file has the following form:
*
*
<?xml version="1.0"?>
*<!DOCTYPE SERVICES SYSTEM "services.dtd">
*<SERVICES>
* <SERVICE NAME="service name" CLASS="fully qualified class name">
* // BeanShell code evaluated when the sevice is first activated
* </SERVICE>
*</SERVICES>
*
* The following elements are valid:
*
*
* -
*
SERVICES
is the top-level element and refers
* to the set of services offered by the plugin.
*
* -
* A
SERVICE
contains the data for a particular service
* activation.
* It has two attributes, both required: NAME
and
* CLASS
. The CLASS
attribute must be the name of
* a known sevice type; see below.
*
* -
* A
SERVICE
element should the BeanShell code that returns a
* new instance of the named class. Note that this code can return
* null
.
*
*
*
* The jEdit core defines the following service types:
*
* - {@link org.gjt.sp.jedit.buffer.FoldHandler}
* - {@link org.gjt.sp.jedit.io.VFS}
* - {@link org.gjt.sp.jedit.io.Encoding}
* - {@link org.gjt.sp.jedit.io.EncodingDetector}
*
*
* Plugins may provide more.
*
* To have your plugin accept services, no extra steps are needed other than
* a piece of code somewhere that calls {@link #getServiceNames(String)} and
* {@link #getService(String,String)}.
*
* @see BeanShell
* @see PluginJAR
*
* @since jEdit 4.2pre1
* @author Slava Pestov
* @version $Id: ServiceManager.java 12504 2008-04-22 23:12:43Z ezust $
*/
public class ServiceManager
{
//{{{ loadServices() method
//{{{ unloadServices() method
//{{{ unregisterService() method
/**
* Unregisters a service.
*
* @param clazz The service class
* @param name The service name
*
* @since jEdit 4.2pre1
*/
public static void unregisterService(String clazz, String name)
{
Descriptor d = new Descriptor(clazz,name);
serviceMap.remove(d);
} //}}}
//{{{ getServiceTypes() method
/**
* Returns all known service class types.
*
* @since jEdit 4.2pre1
*/
public static String[] getServiceTypes()
{
Set returnValue = new HashSet();
Set keySet = serviceMap.keySet();
for (Descriptor d : keySet)
returnValue.add(d.clazz);
return returnValue.toArray(
new String[returnValue.size()]);
} //}}}
//{{{ getServiceNames() method
/**
* Returns the names of all registered services with the given
* class. For example, calling this with a parameter of
* "org.gjt.sp.jedit.io.VFS" returns all known virtual file
* systems.
*
* @param clazz The class name
* @since jEdit 4.2pre1
*/
public static String[] getServiceNames(String clazz)
{
List returnValue = new ArrayList();
Set keySet = serviceMap.keySet();
for (Descriptor d : keySet)
if(d.clazz.equals(clazz))
returnValue.add(d.name);
return returnValue.toArray(
new String[returnValue.size()]);
} //}}}
//{{{ getService() method
/**
* Returns an instance of the given service. The first time this is
* called for a given service, the BeanShell code is evaluated. The
* result is cached for future invocations, so in effect services are
* singletons.
*
* @param clazz The service class
* @param name The service name
* @since jEdit 4.2pre1
*/
public static Object getService(String clazz, String name)
{
// they never taught you this in undergrad computer science
Descriptor key = new Descriptor(clazz,name);
Descriptor value = serviceMap.get(key);
if(value == null)
{
// unknown service - not in table
return null;
}
else
{
if(value.code == null)
{
value = serviceMap.get(key);
}
return value.getInstance();
}
} //}}}
//{{{ Package-private members
//{{{ registerService() method
/**
* Registers a service.
*
* @since jEdit 4.2pre1
*/
static void registerService(Descriptor d)
{
serviceMap.put(d,d);
} //}}}
//}}}
//{{{ Private members
private static final Map serviceMap = new HashMap();
//}}}
//{{{ Descriptor class
static class Descriptor
{
final String clazz;
final String name;
String code;
Object instance;
boolean instanceIsNull;
// this constructor keys the hash table
Descriptor(String clazz, String name)
{
this.clazz = clazz;
this.name = name;
}
// this constructor is the value of the hash table
Object getInstance()
{
if(instanceIsNull)
return null;
else if(instance == null)
{
if(instance == null)
{
// avoid re-running script if it gives
// us null
instanceIsNull = true;
}
}
return instance;
}
public int hashCode()
{
return name.hashCode();
}
public boolean equals(Object o)
{
if(o instanceof Descriptor)
{
Descriptor d = (Descriptor)o;
return d.clazz.equals(clazz)
&& d.name.equals(name);
}
else
return false;
}
} //}}}
/**
* A FoldHandler based on the ServiceManager
* @author Matthieu Casanova
* @since jEdit 4.3pre10
*/
public static class ServiceFoldHandlerProvider implements FoldHandlerProvider
{
/**
* The service type. See {@link org.gjt.sp.jedit.ServiceManager}.
* @since jEdit 4.3pre10
*/
public static final String SERVICE = "org.gjt.sp.jedit.buffer.FoldHandler";
/**
* Returns the fold handler with the specified name, or null if
* there is no registered handler with that name.
* @param name The name of the desired fold handler
* @return the FoldHandler or null if it doesn't exists
* @since jEdit 4.3pre10
*/
public FoldHandler getFoldHandler(String name)
{
FoldHandler handler = (FoldHandler) getService(SERVICE,name);
return handler;
}
/**
* Returns an array containing the names of all registered fold
* handlers.
*
* @since jEdit 4.3pre10
*/
public String[] getFoldModes()
{
String[] handlers = getServiceNames(SERVICE);
Arrays.sort(handlers,new StandardUtilities.StringCompare());
return handlers;
}
}
}