企业搜索引擎开发之连接器connector(四)

实例化类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&lt;String, String&gt; 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成员变量

原文地址:https://www.cnblogs.com/chenying99/p/2964148.html