实例化类Instantiator的功能主要是提供操作连接器实例的一些接口,基本上servlet对外提供的接口最终都会调用实例化类的相关方法

先浏览一下Instantiator接口的源码



/**
* Interface for instantiator component.
*/
public interface Instantiator {

/**
* gets an AuthenticationManager for a named connector.
*
* @param connectorName the String name of the connector for which to get the
* Traverser
* @return the AuthenticationManager, fully instantiated
* @throws ConnectorNotFoundException to indicate that no connector of the
* specified name is found
* @throws InstantiatorException if something bad, probably unrecoverable,
* happens
*/
public AuthenticationManager getAuthenticationManager(String connectorName)
throws ConnectorNotFoundException, InstantiatorException;

/**
* gets an AuthorizationManager for a named connector.
*
* @param connectorName the String name of the connector for which to get the
* Traverser
* @return the AuthorizationManager, fully instantiated
* @throws ConnectorNotFoundException to indicate that no connector of the
* specified name is found
* @throws InstantiatorException if something bad, probably unrecoverable,
* happens
*/
public AuthorizationManager getAuthorizationManager(String connectorName)
throws ConnectorNotFoundException, InstantiatorException;

/**
* Restart the Traverser for the named connector.
* This resets the Traverser, re-indexing the repository from scratch.
*
* @param connectorName
* @throws ConnectorNotFoundException
* @throws InstantiatorException
*/
public void restartConnectorTraversal(String connectorName)
throws ConnectorNotFoundException, InstantiatorException;

/**
* Removes a named connector.
*
* @param connectorName
* @throws InstantiatorException
*/
public void removeConnector(String connectorName) throws InstantiatorException;

/**
* Finds a named connector type.
*
* @param connectorTypeName The connector type to find
* @return the ConnectorType, fully instantiated
* @throws ConnectorTypeNotFoundException if the connector type is not found
*/
public ConnectorType getConnectorType(String connectorTypeName)
throws ConnectorTypeNotFoundException;

/**
* Gets all the known connector type names.
*
* @return a Set of String names
*/
public Set<String> getConnectorTypeNames();

/**
* Gets the prototype definition for instances of this type
*
* @param connectorTypeName The connector type for which to get the prototype
* @return prototype String
* @throws ConnectorTypeNotFoundException if the connector type is not found
* @see ConnectorType#getConfigForm(Locale)
*/
public String getConnectorInstancePrototype(String connectorTypeName)
throws ConnectorTypeNotFoundException;

/**
* Get configuration form snippet populated with values representing the
* configuration of the supplied connector.
*
* @param connectorName the connector whose configuration should be used to
* populate the form snippet.
* @param connectorTypeName The connector type for which to get the prototype
* @param locale A java.util.Locale which the implementation may use to
* produce appropriate descriptions and messages.
* @return a ConfigureResponse object. The form must be prepopulated with the
* data from the supplied connector instance's configuration.
* @see ConnectorType#getPopulatedConfigForm(Map, Locale)
*/
public ConfigureResponse getConfigFormForConnector(String connectorName,
String connectorTypeName, Locale locale)
throws ConnectorNotFoundException, InstantiatorException;

/**
* Get the names of all known connector instances.
*
* @return a Set of String names
*/
public Set<String> getConnectorNames();

/**
* Get the type for a known connector
*
* @param connectorName the connector to look up
* @return its type, as a String
* @throws ConnectorNotFoundException if the named connector is not found
*/
public String getConnectorTypeName(String connectorName)
throws ConnectorNotFoundException;

/**
* Sets the configuration for a new connector. This connector should not
* exist.
*
* @param connectorName The connector to create
* @param connectorTypeName The type for this connector
* @param configMap A configuration map for this connector
* @param locale A Java Locale string
* @param update A boolean true if updating the existing connector
* @return null if config is valid and accepted, a ConfigureResponse object
* if config is invalid.
* @throws ConnectorNotFoundException
* @throws ConnectorExistsException
* @throws ConnectorTypeNotFoundException
* @throws InstantiatorException
*/
public ConfigureResponse setConnectorConfig(String connectorName,
String connectorTypeName, Map<String, String> configMap, Locale locale,
boolean update)
throws ConnectorNotFoundException, ConnectorExistsException,
ConnectorTypeNotFoundException, InstantiatorException;

/**
* Get a connector's ConnectorType-specific configuration data
*
* @param connectorName the connector to look up
* @return a Map<String, String> of its ConnectorType-specific
* configuration data
* @throws ConnectorNotFoundException if the named connector is not found
*/
public Map<String, String> getConnectorConfig(String connectorName)
throws ConnectorNotFoundException;

/**
* Sets the schedule of a named connector.
*
* @param connectorName
* @param connectorSchedule String to store or null unset any existing
* schedule.
* @throws ConnectorNotFoundException if the named connector is not found
*/
public void setConnectorSchedule(String connectorName,
String connectorSchedule) throws ConnectorNotFoundException;

/**
* Gets the schedule of a named connector.
*
* @param connectorName
* @return the schedule String, or null if there is no stored schedule
* for this connector.
* @throws ConnectorNotFoundException if the named connector is not found
*/
public String getConnectorSchedule(String connectorName)
throws ConnectorNotFoundException;

/**
* Returns the named {@link ConnectorCoordinator}.
*
* @throws ConnectorNotFoundException if the named connector is not found
*/
public ConnectorCoordinator getConnectorCoordinator(
String connectorName) throws ConnectorNotFoundException;

/**
* Shutdown all the Connector instances.
*/
public void shutdown(boolean interrupt, long timeoutMillis);
}


 这些接口方法名跟上文uml模型图示的servlet名极为相似,因为servlet里面的执行方法最终都要调用该接口实现类的相关方法

实现类SpringInstantiator提供上述方法的具体实现,其源码如下:



/**
* {@link Instantiator} that supports Spring based connector instantiation and
* persistent storage of connector configuration, schedule and traversal state.
*/
public class SpringInstantiator implements Instantiator {

private static final Logger LOGGER =
Logger.getLogger(SpringInstantiator.class.getName());

private final ConcurrentMap<String, ConnectorCoordinator> coordinatorMap;

// State that is filled in by setters from Spring.
private PusherFactory pusherFactory;
private LoadManagerFactory loadManagerFactory;
private ThreadPool threadPool;

// State that is filled in by init.
private TypeMap typeMap;

/**
* Normal constructor.
*/
public SpringInstantiator() {
this.coordinatorMap = new ConcurrentHashMap<String, ConnectorCoordinator>();

// NOTE: we can't call init() here because then there would be a
// circular dependency on the Context, which hasn't been constructed yet
}

/**
* Sets the {@link PusherFactory} used to create instances of
* {@link com.google.enterprise.connector.pusher.Pusher Pusher}
* for pushing documents to the GSA.
*
* @param pusherFactory a {@link PusherFactory} implementation.
*/
public void setPusherFactory(PusherFactory pusherFactory) {
this.pusherFactory = pusherFactory;
}

/**
* Sets the {@link LoadManagerFactory} used to create instances of
* {@link com.google.enterprise.connector.scheduler.LoadManager LoadManager}
* for controlling feed rate.
*
* @param loadManagerFactory a {@link LoadManagerFactory}.
*/
public void setLoadManagerFactory(LoadManagerFactory loadManagerFactory) {
this.loadManagerFactory = loadManagerFactory;
}

/**
* Sets the {@link ThreadPool} used for running traversals.
*
* @param threadPool a {@link ThreadPool} implementation.
*/
public void setThreadPool(ThreadPool threadPool) {
this.threadPool = threadPool;
}

/**
* Sets the {@link TypeMap} of installed {@link ConnectorType}s.
*
* @param typeMap a {@link TypeMap}.
*/
public void setTypeMap(TypeMap typeMap) {
this.typeMap = typeMap;
}

/**
* Initializes the Context, post bean construction.
*/
public synchronized void init() {
LOGGER.info("Initializing instantiator");
if (typeMap == null) {
setTypeMap(new TypeMap());
}
ConnectorCoordinatorMapHelper.fillFromTypes(typeMap, coordinatorMap,
pusherFactory, loadManagerFactory, threadPool);
}

/**
* Shutdown all connector instances.
*/
public void shutdown(boolean interrupt, long timeoutMillis) {
for (ConnectorCoordinator cc : coordinatorMap.values()) {
cc.shutdown();
}
try {
if (threadPool != null) {
threadPool.shutdown(interrupt, timeoutMillis);
}
} catch (InterruptedException ie) {
LOGGER.log(Level.SEVERE, "TraversalScheduler shutdown interrupted: ", ie);
}
}

public void removeConnector(String connectorName) {
LOGGER.info("Dropping connector: " + connectorName);
ConnectorCoordinator existing = coordinatorMap.get(connectorName);
if (existing != null) {
existing.removeConnector();
}
}

public AuthenticationManager getAuthenticationManager(String connectorName)
throws ConnectorNotFoundException, InstantiatorException {
return getConnectorCoordinator(connectorName).getAuthenticationManager();
}

public ConnectorCoordinator getConnectorCoordinator(
String connectorName) throws ConnectorNotFoundException {
ConnectorCoordinator connectorCoordinator =
coordinatorMap.get(connectorName);
if (connectorCoordinator == null) {
throw new ConnectorNotFoundException();
}
return connectorCoordinator;
}

private ConnectorCoordinator getOrAddConnectorCoordinator(
String connectorName) {
if (typeMap == null) {
throw new IllegalStateException(
"Init must be called before accessing connectors.");
}
ConnectorCoordinator connectorCoordinator =
coordinatorMap.get(connectorName);
if (connectorCoordinator == null) {
ConnectorCoordinator ci = new ConnectorCoordinatorImpl(
connectorName, pusherFactory, loadManagerFactory, threadPool);
ConnectorCoordinator existing =
coordinatorMap.putIfAbsent(connectorName, ci);
connectorCoordinator = (existing == null) ? ci : existing;
}
return connectorCoordinator;
}

public AuthorizationManager getAuthorizationManager(String connectorName)
throws ConnectorNotFoundException, InstantiatorException {
return getConnectorCoordinator(connectorName).getAuthorizationManager();
}

public ConfigureResponse getConfigFormForConnector(String connectorName,
String connectorTypeName, Locale locale)
throws ConnectorNotFoundException, InstantiatorException {
return getConnectorCoordinator(connectorName).getConfigForm(locale);
}

public String getConnectorInstancePrototype(String connectorTypeName) {
throw new UnsupportedOperationException();
}

public synchronized ConnectorType getConnectorType(String typeName)
throws ConnectorTypeNotFoundException {
return getTypeInfo(typeName).getConnectorType();
}

private TypeInfo getTypeInfo(String typeName)
throws ConnectorTypeNotFoundException {
TypeInfo typeInfo = typeMap.getTypeInfo(typeName);
if (typeInfo == null) {
throw new ConnectorTypeNotFoundException("Connector Type not found: "
+ typeName);
}
return typeInfo;
}

public synchronized Set<String> getConnectorTypeNames() {
return Collections.unmodifiableSet(new TreeSet<String>(typeMap.keySet()));
}

public void restartConnectorTraversal(String connectorName)
throws ConnectorNotFoundException {
LOGGER.info("Restarting traversal for Connector: " + connectorName);
getConnectorCoordinator(connectorName).restartConnectorTraversal();
}

public Set<String> getConnectorNames() {
Set<String> result = new TreeSet<String>();
for (Map.Entry<String, ConnectorCoordinator> e :
coordinatorMap.entrySet()) {
if (e.getValue().exists()) {
result.add(e.getKey());
}
}
return Collections.unmodifiableSet(result);
}

public String getConnectorTypeName(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorTypeName();
}

public ConfigureResponse setConnectorConfig(String connectorName,
String connectorTypeName, Map<String, String> configMap, Locale locale,
boolean update) throws ConnectorNotFoundException,
ConnectorExistsException, InstantiatorException {
LOGGER.info("Configuring connector: " + connectorName);
try {
TypeInfo typeInfo = getTypeInfo(connectorTypeName);
ConnectorCoordinator ci = getOrAddConnectorCoordinator(connectorName);
return ci.setConnectorConfig(typeInfo, configMap, locale, update);
} catch (ConnectorTypeNotFoundException ctnf) {
throw new ConnectorNotFoundException("Incorrect type", ctnf);
}
}

public Map<String, String> getConnectorConfig(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorConfig();
}

public void setConnectorSchedule(String connectorName,
String connectorSchedule) throws ConnectorNotFoundException {
getConnectorCoordinator(connectorName).
setConnectorSchedule(connectorSchedule);
}

public String getConnectorSchedule(String connectorName)
throws ConnectorNotFoundException {
return getConnectorCoordinator(connectorName).getConnectorSchedule();
}
}


 该类依赖的实际是TypeMap类与ConnectorCoordinator类,主要是ConnectorCoordinator类,至于PusherFactory LoadManagerFactory ThreadPool三类,是在构造ConnectorCoordinator对象时通过构造函数传参传递过去的,其他地方只是在void shutdown(boolean interrupt, long timeoutMillis)方法调用了成员ThreadPool的boolean shutdown(boolean interrupt, long waitMillis)方法

先看它的初始化方法



/**
* Initializes the Context, post bean construction.
*/
public synchronized void init() {
LOGGER.info("Initializing instantiator");
if (typeMap == null) {
setTypeMap(new TypeMap());
}
ConnectorCoordinatorMapHelper.fillFromTypes(typeMap, coordinatorMap,
pusherFactory, loadManagerFactory, threadPool);
}


 

这里主要是初始化TypeMap typeMap成员变量和ConcurrentMap<String, ConnectorCoordinator> coordinatorMap成员变量

TypeMap类的源码如下:



/**
* This class keeps track of the installed connector types and maintains a
* corresponding directory structure.
*/
public class TypeMap extends TreeMap<String, TypeInfo> {

private static final String CONNECTOR_TYPE_PATTERN =
"classpath*:config/connectorType.xml";

private static final Logger LOGGER =
Logger.getLogger(TypeMap.class.getName());

public TypeMap() {
initialize(CONNECTOR_TYPE_PATTERN, null);
}

/**
* For testing only. Either parameter may be null, in which case the default
* is used.
*
* @param connectorTypePattern used instead of normal default
* @param baseDirPath
*/
public TypeMap(String connectorTypePattern, String baseDirPath) {
initialize(connectorTypePattern, baseDirPath);
}

private File baseDirectory = null;
private File typesDirectory = null;

private void initialize(String connectorTypePattern, String baseDirPath) {
initializeTypes(connectorTypePattern);
initializeBaseDirectories(baseDirPath);
initializeTypeDirectories();
}

private void initializeTypes(String connectorTypePattern) {
ApplicationContext ac = Context.getInstance().getApplicationContext();

Resource[] resourceArray;
try {
resourceArray = ac.getResources(connectorTypePattern);
} catch (IOException e) {
LOGGER.log(Level.WARNING, "IOException from Spring while getting "
+ connectorTypePattern
+ " resources. No connector types can be found", e);
return;
}

if (resourceArray.length == 0) {
LOGGER.info("No connector types found.");
return;
}

for (Resource r : resourceArray) {
TypeInfo typeInfo = TypeInfo.fromSpringResource(r);
if (typeInfo == null) {
LOGGER.log(Level.WARNING, "Skipping " + r.getDescription());
continue;
}
this.put(typeInfo.getConnectorTypeName(), typeInfo);
LOGGER.info("Found connector type: " + typeInfo.getConnectorTypeName()
+ " version: "
+ JarUtils.getJarVersion(typeInfo.getConnectorType().getClass()));
}
}

private void initializeDefaultBaseDirectory() {
String commonDirPath = Context.getInstance().getCommonDirPath();
baseDirectory = new File(commonDirPath);
}

private void initializeBaseDirectories(String baseDirPath) {
if (baseDirPath == null) {
initializeDefaultBaseDirectory();
} else {
baseDirectory = new File(baseDirPath);
}

typesDirectory = new File(baseDirectory, "connectors");
if (!typesDirectory.exists()) {
if (!typesDirectory.mkdirs()) {
throw new IllegalStateException("Can't create connector types directory "
+ typesDirectory.getPath());
}
}

if (!typesDirectory.isDirectory()) {
throw new IllegalStateException("Unexpected file "
+ typesDirectory.getPath() + " blocks creation of types directory");
}
}

public TypeInfo getTypeInfo(String connectorTypeName) {
return this.get(connectorTypeName);
}

private void initializeTypeDirectories() {
for (Iterator<String> iter = keySet().iterator(); iter.hasNext(); ) {
String typeName = iter.next();
TypeInfo typeInfo = getTypeInfo(typeName);
File connectorTypeDir = new File(typesDirectory, typeName);
if (!connectorTypeDir.exists()) {
if(!connectorTypeDir.mkdirs()) {
LOGGER.warning("Type " + typeName
+ " has a valid definition but no type directory - skipping it");
iter.remove();
return;
}
}
if (!typesDirectory.isDirectory()) {
LOGGER.warning("Unexpected file " + connectorTypeDir.getPath()
+ " blocks creation of instances directory for type " + typeName
+ " - skipping it");
iter.remove();
} else {
typeInfo.setConnectorTypeDir(connectorTypeDir);
LOGGER.info("Connector type: " + typeInfo.getConnectorTypeName()
+ " has directory " + connectorTypeDir.getAbsolutePath());
}
}
}
}


该类的注释很清楚,用于检测已安装的连接器类型并维持相应的导航结构

ConnectorCoordinatorMapHelper类的源码如下:



/**
* Utility functions for operations on a {@link ConcurrentMap} of
* {@link String} connector coordinator name to {@link ConnectorCoordinator}
* Objects.
*/
class ConnectorCoordinatorMapHelper {
private static final Logger LOGGER =
Logger.getLogger(ConnectorCoordinatorMapHelper.class.getName());

private ConnectorCoordinatorMapHelper() { // Prevents instantiation.
}

/**
* Initializes <b>instanceMap</b> to contain a {@link ConnectorCoordinator}
* for each connector defined in the provided {@link TypeMap}.
*
* @param pusherFactory creates instances of
* {@link com.google.enterprise.connector.pusher.Pusher Pusher}
* for pushing documents to the GSA.
* @param loadManagerFactory creates instances of
* {@link com.google.enterprise.connector.scheduler.LoadManager LoadManager}
* used for controlling feed rate.
* @param threadPool the {@link ThreadPool} for running traversals.
*/
static void fillFromTypes(TypeMap typeMap,
ConcurrentMap<String, ConnectorCoordinator> instanceMap,
PusherFactory pusherFactory, LoadManagerFactory loadManagerFactory,
ThreadPool threadPool) {
for (String typeName : typeMap.keySet()) {
TypeInfo typeInfo = typeMap.getTypeInfo(typeName);
if (typeInfo == null) {
LOGGER.log(Level.WARNING, "Skipping " + typeName);
continue;
}
processTypeDirectory(instanceMap, typeInfo, pusherFactory,
loadManagerFactory, threadPool);
}
}

/**
* Initializes <b>instanceMap</b> to contain a {@link ConnectorCoordinator}
* for each connector defined in the provided {@link TypeInfo}.
*
* @param pusherFactory creates instances of
* {@link com.google.enterprise.connector.pusher.Pusher Pusher}
* for pushing documents to the GSA.
* @param loadManagerFactory creates instances of
* {@link com.google.enterprise.connector.scheduler.LoadManager LoadManager}
* used for controlling feed rate.
* @param threadPool the {@link ThreadPool} for running traversals.
*/
private static void processTypeDirectory(
ConcurrentMap<String, ConnectorCoordinator> instanceMap,
TypeInfo typeInfo, PusherFactory pusherFactory,
LoadManagerFactory loadManagerFactory, ThreadPool threadPool) {
File typeDirectory = typeInfo.getConnectorTypeDir();

// Find the subdirectories.
FileFilter fileFilter = new FileFilter() {
public boolean accept(File file) {
return file.isDirectory() && !file.getName().startsWith(".");
}
};
File[] directories = typeDirectory.listFiles(fileFilter);

if (directories == null) {
// This just means the directory is empty.
return;
}

// Process each one.
for (int i = 0; i < directories.length; i++) {
File directory = directories[i];
String name = directory.getName();
NDC.pushAppend(name);
try {
InstanceInfo instanceInfo =
InstanceInfo.fromDirectory(name, directory, typeInfo);
if (instanceInfo != null) {
ConnectorCoordinator fromType = new ConnectorCoordinatorImpl(
instanceInfo, pusherFactory, loadManagerFactory, threadPool);
ConnectorCoordinator current =
instanceMap.putIfAbsent(name, fromType);
if (current != null) {
throw new IllegalStateException(
"Connector instance modified during initialization");
}
}

} catch (InstantiatorException e) {
LOGGER.log(Level.WARNING, "Problem creating connector instance", e);
} finally {
NDC.pop();
}
}
}
}


该类提供静态方法,用于初始化ConcurrentMap<String, ConnectorCoordinator> instanceMap成员变量