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

  • 相关阅读:
    Atitit 引流矩阵与矩阵引流 推广方法 attilax总结
    Atitit 怎么阅读一本书 消化 分析 检索 attilax总结 1. 读书的本质 是数据的处理,大量的数据,处理能力有限的大脑 2 2. ETL数据清洗转换 摘要,缩小数据规模 2 2.1
    Atitit 为什么要读书,读书的好处是什么 attilax总结
    Atititi. naming spec 联系人命名与remark备注指南规范v5 r99.docx
    Atitit 安全规范 指南 常见五种意外防止规范 attilax总结
    数据安全 密码学原理与概论
    Atitit 理财之道分期与利率的比较列表 attilax总结
    Atitit 完整知识体系表 attilax总结 要读哪些书
    Atitit 为什么互联网机会这么大
    Atitit 建立新组织集团模型的框架基本制度与一些原则
  • 原文地址:https://www.cnblogs.com/chenying99/p/2964148.html
Copyright © 2020-2023  润新知