实例化类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成员变量