View Javadoc
1   /*
2    * Copyright 2012-2021 CodeLibs Project and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.codelibs.fess.ds;
17  
18  import java.io.File;
19  import java.io.InputStream;
20  import java.nio.file.FileSystem;
21  import java.nio.file.FileSystems;
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.util.HashSet;
25  import java.util.LinkedHashMap;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.Map;
29  import java.util.Set;
30  import java.util.stream.Collectors;
31  
32  import javax.xml.parsers.DocumentBuilder;
33  import javax.xml.parsers.DocumentBuilderFactory;
34  
35  import org.apache.logging.log4j.LogManager;
36  import org.apache.logging.log4j.Logger;
37  import org.codelibs.core.lang.StringUtil;
38  import org.codelibs.fess.Constants;
39  import org.codelibs.fess.helper.PluginHelper;
40  import org.codelibs.fess.util.ResourceUtil;
41  import org.w3c.dom.Document;
42  import org.w3c.dom.NamedNodeMap;
43  import org.w3c.dom.Node;
44  import org.w3c.dom.NodeList;
45  
46  public class DataStoreFactory {
47      private static final Logger logger = LogManager.getLogger(DataStoreFactory.class);
48  
49      protected Map<String, DataStore> dataStoreMap = new LinkedHashMap<>();
50  
51      protected String[] dataStoreNames = StringUtil.EMPTY_STRINGS;
52  
53      protected long lastLoadedTime = 0;
54  
55      public void add(final String name, final DataStore dataStore) {
56          if (name == null || dataStore == null) {
57              throw new IllegalArgumentException("name or dataStore is null.");
58          }
59          if (logger.isDebugEnabled()) {
60              logger.debug("Loaded {}", name);
61          }
62          dataStoreMap.put(name.toLowerCase(Locale.ROOT), dataStore);
63          dataStoreMap.put(dataStore.getClass().getSimpleName().toLowerCase(Locale.ROOT), dataStore);
64      }
65  
66      public DataStore getDataStore(final String name) {
67          if (name == null) {
68              return null;
69          }
70          return dataStoreMap.get(name.toLowerCase(Locale.ROOT));
71      }
72  
73      public String[] getDataStoreNames() {
74          final long now = System.currentTimeMillis();
75          if (now - lastLoadedTime > 60000L) {
76              final List<String> nameList = loadDataStoreNameList();
77              dataStoreNames = nameList.toArray(n -> new String[nameList.size()]);
78              lastLoadedTime = now;
79          }
80          return dataStoreNames;
81      }
82  
83      protected List<String> loadDataStoreNameList() {
84          final Set<String> nameSet = new HashSet<>();
85          final File[] jarFiles = ResourceUtil.getPluginJarFiles(PluginHelper.ArtifactType.DATA_STORE.getId());
86          for (final File jarFile : jarFiles) {
87              try (FileSystem fs = FileSystems.newFileSystem(jarFile.toPath(), ClassLoader.getSystemClassLoader())) {
88                  final Path xmlPath = fs.getPath("fess_ds++.xml");
89                  try (InputStream is = Files.newInputStream(xmlPath)) {
90                      final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
91                      factory.setFeature(org.codelibs.fess.crawler.Constants.FEATURE_SECURE_PROCESSING, true);
92                      factory.setFeature(org.codelibs.fess.crawler.Constants.FEATURE_EXTERNAL_GENERAL_ENTITIES, false);
93                      factory.setFeature(org.codelibs.fess.crawler.Constants.FEATURE_EXTERNAL_PARAMETER_ENTITIES, false);
94                      factory.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE, false);
95                      final DocumentBuilder builder = factory.newDocumentBuilder();
96  
97                      final Document doc = builder.parse(is);
98                      final NodeList nodeList = doc.getElementsByTagName("component");
99                      for (int i = 0; i < nodeList.getLength(); i++) {
100                         final Node node = nodeList.item(i);
101                         final NamedNodeMap attributes = node.getAttributes();
102                         if (attributes != null) {
103                             final Node classAttr = attributes.getNamedItem("class");
104                             if (classAttr != null) {
105                                 final String value = classAttr.getNodeValue();
106                                 if (StringUtil.isNotBlank(value)) {
107                                     final String[] values = value.split("\\.");
108                                     nameSet.add(values[values.length - 1]);
109                                 }
110                             }
111                         }
112                     }
113                 }
114             } catch (final Exception e) {
115                 logger.warn("Failed to load {}", jarFile.getAbsolutePath(), e);
116             }
117         }
118         return nameSet.stream().sorted().collect(Collectors.toList());
119     }
120 
121 }