企业搜索引擎开发之连接器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成员变量

你可能感兴趣的:(connector)