View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.openr66.dao.xml;
22  
23  import org.w3c.dom.Document;
24  import org.w3c.dom.Element;
25  import org.w3c.dom.Node;
26  import org.w3c.dom.NodeList;
27  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
28  import org.waarp.common.logging.WaarpLogger;
29  import org.waarp.common.logging.WaarpLoggerFactory;
30  import org.waarp.common.xml.XmlUtil;
31  import org.waarp.openr66.configuration.ExtensionFilter;
32  import org.waarp.openr66.dao.Filter;
33  import org.waarp.openr66.dao.RuleDAO;
34  import org.waarp.openr66.dao.exception.DAOConnectionException;
35  import org.waarp.openr66.dao.exception.DAONoDataException;
36  import org.waarp.openr66.pojo.Rule;
37  import org.waarp.openr66.pojo.RuleTask;
38  import org.waarp.openr66.protocol.configuration.Configuration;
39  import org.xml.sax.SAXException;
40  
41  import javax.xml.parsers.DocumentBuilderFactory;
42  import javax.xml.parsers.ParserConfigurationException;
43  import javax.xml.xpath.XPath;
44  import javax.xml.xpath.XPathConstants;
45  import javax.xml.xpath.XPathExpression;
46  import javax.xml.xpath.XPathExpressionException;
47  import javax.xml.xpath.XPathFactory;
48  import java.io.File;
49  import java.io.IOException;
50  import java.util.ArrayList;
51  import java.util.Arrays;
52  import java.util.List;
53  import java.util.concurrent.ConcurrentHashMap;
54  
55  import static org.waarp.openr66.dao.DAOFactory.*;
56  import static org.waarp.openr66.dao.database.DBRuleDAO.*;
57  
58  public class XMLRuleDAO implements RuleDAO {
59  
60    private static final WaarpLogger logger =
61        WaarpLoggerFactory.getLogger(XMLRuleDAO.class);
62  
63    /**
64     * HashTable in case of lack of database
65     */
66    private static final ConcurrentHashMap<String, Rule> dbR66RuleHashMap =
67        new ConcurrentHashMap<String, Rule>();
68  
69    public static final String ROOT_LIST = "rules";
70  
71    private static final String XML_GET_ALL = "//rule";
72    private static final File[] FILE_0_LENGTH = new File[0];
73  
74    public XMLRuleDAO() {
75      // Nothing to do
76    }
77  
78    @Override
79    public final void close() {
80      // ignore
81    }
82  
83    public static final String EXT_RULE = ".rule.xml";
84    public static final String EXT_RULES = ".rules.xml";
85  
86    private File[] getRuleFiles() {
87      final File ruleDir = new File(
88          Configuration.configuration.getBaseDirectory() +
89          Configuration.configuration.getConfigPath());
90      final List<File> res = new ArrayList<File>();
91      if (ruleDir.isDirectory()) {
92        res.addAll(
93            Arrays.asList(ruleDir.listFiles(new ExtensionFilter(EXT_RULE))));
94        res.addAll(
95            Arrays.asList(ruleDir.listFiles(new ExtensionFilter(EXT_RULES))));
96      }
97      return res.toArray(FILE_0_LENGTH);
98    }
99  
100   @Override
101   public final void delete(final Rule rule) {
102     dbR66RuleHashMap.remove(rule.getName());
103   }
104 
105   @Override
106   public final void deleteAll() {
107     dbR66RuleHashMap.clear();
108   }
109 
110   @Override
111   public final List<Rule> getAll() throws DAOConnectionException {
112     final List<Rule> res = new ArrayList<Rule>();
113 
114     final File[] files = getRuleFiles();
115     for (final File ruleFile : files) {
116       logger.debug("Load file {}", ruleFile.getAbsolutePath());
117       try {
118         final DocumentBuilderFactory dbf = getDocumentBuilderFactory();
119         final Document document = dbf.newDocumentBuilder().parse(ruleFile);
120         // Setup XPath query
121         final XPath xPath = XPathFactory.newInstance().newXPath();
122         final XPathExpression xpe = xPath.compile(XML_GET_ALL);
123         final NodeList listNode =
124             (NodeList) xpe.evaluate(document, XPathConstants.NODESET);
125         // Iterate through all found nodes
126 
127         for (int i = 0; i < listNode.getLength(); i++) {
128           final Node node = listNode.item(i);
129           final Rule rule = getFromNode(node);
130           res.add(rule);
131           dbR66RuleHashMap.put(rule.getName(), rule);
132         }
133       } catch (final SAXException e) {
134         throw new DAOConnectionException(e);
135       } catch (final XPathExpressionException e) {
136         throw new DAOConnectionException(e);
137       } catch (final ParserConfigurationException e) {
138         throw new DAOConnectionException(e);
139       } catch (final IOException e) {
140         throw new DAOConnectionException(e);
141       } catch (final Exception e) {
142         throw new DAOConnectionException(e);
143       }
144     }
145     return res;
146   }
147 
148   /**
149    * {@link DAOConnectionException}
150    *
151    * @return count only if filters is empty or null
152    */
153   @Override
154   public final long count(final List<Filter> fitlers)
155       throws DAOConnectionException {
156     if (fitlers == null || fitlers.isEmpty()) {
157       return dbR66RuleHashMap.size();
158     }
159     throw new DAOConnectionException("Operation not supported on XML DAO");
160   }
161 
162   @Override
163   public final boolean exist(final String rulename) {
164     return dbR66RuleHashMap.containsKey(rulename);
165   }
166 
167   @Override
168   public final List<Rule> find(final List<Filter> fitlers)
169       throws DAOConnectionException {
170     throw new DAOConnectionException("Operation not supported on XML DAO");
171   }
172 
173   @Override
174   public List<Rule> find(final List<Filter> filters, final int limit)
175       throws DAOConnectionException {
176     throw new DAOConnectionException("Operation not supported on XML DAO");
177   }
178 
179   @Override
180   public List<Rule> find(final List<Filter> filters, final String field,
181                          final boolean asc) throws DAOConnectionException {
182     throw new DAOConnectionException("Operation not supported on XML DAO");
183   }
184 
185   @Override
186   public List<Rule> find(final List<Filter> filters, final String field,
187                          final boolean asc, final int limit)
188       throws DAOConnectionException {
189     throw new DAOConnectionException("Operation not supported on XML DAO");
190   }
191 
192   @Override
193   public List<Rule> find(final List<Filter> filters, final String field,
194                          final boolean asc, final int limit, final int offset)
195       throws DAOConnectionException {
196     throw new DAOConnectionException("Operation not supported on XML DAO");
197   }
198 
199   @Override
200   public void update(final List<Filter> filters, final String toSet)
201       throws DAOConnectionException {
202     throw new DAOConnectionException("Operation not supported on XML DAO");
203   }
204 
205   @Override
206   public final void insert(final Rule rule) {
207     dbR66RuleHashMap.put(rule.getName(), rule);
208   }
209 
210   @Override
211   public final Rule select(final String rulename)
212       throws DAOConnectionException, DAONoDataException {
213     if (exist(rulename)) {
214       return dbR66RuleHashMap.get(rulename);
215     }
216     throw new DAONoDataException("Rule cannot be found");
217   }
218 
219   @Override
220   public final void update(final Rule rule) {
221     dbR66RuleHashMap.put(rule.getName(), rule);
222   }
223 
224   private Rule getFromNode(final Node parent) throws DAOConnectionException {
225     final Rule res = new Rule();
226 
227     final NodeList children = parent.getChildNodes();
228     for (int j = 0; j < children.getLength(); j++) {
229       final Node node = children.item(j);
230       final String content = XmlUtil.getExtraTrimed(node.getTextContent());
231       if (node.getNodeName().equals(ID_FIELD)) {
232         res.setName(content);
233       } else if (node.getNodeName().equals(HOSTIDS_FIELD)) {
234         res.setHostids(retrieveHostids(node));
235       } else if (node.getNodeName().equals(MODE_TRANS_FIELD)) {
236         res.setMode(Integer.parseInt(content));
237       } else if (node.getNodeName().equals(SEND_PATH_FIELD)) {
238         try {
239           res.setSendPath(content);
240         } catch (final WaarpDatabaseSqlException e) {
241           throw new DAOConnectionException(e);
242         }
243       } else if (node.getNodeName().equals(RECV_PATH_FIELD)) {
244         try {
245           res.setRecvPath(content);
246         } catch (final WaarpDatabaseSqlException e) {
247           throw new DAOConnectionException(e);
248         }
249       } else if (node.getNodeName().equals(ARCHIVE_PATH_FIELD)) {
250         try {
251           res.setArchivePath(content);
252         } catch (final WaarpDatabaseSqlException e) {
253           throw new DAOConnectionException(e);
254         }
255       } else if (node.getNodeName().equals(WORK_PATH_FIELD)) {
256         try {
257           res.setWorkPath(content);
258         } catch (final WaarpDatabaseSqlException e) {
259           throw new DAOConnectionException(e);
260         }
261       } else if (node.getNodeName().equals(R_PRE_TASKS_FIELD)) {
262         res.setRPreTasks(retrieveTasks(node));
263       } else if (node.getNodeName().equals(R_POST_TASKS_FIELD)) {
264         res.setRPostTasks(retrieveTasks(node));
265       } else if (node.getNodeName().equals(R_ERROR_TASKS_FIELD)) {
266         res.setRErrorTasks(retrieveTasks(node));
267       } else if (node.getNodeName().equals(S_PRE_TASKS_FIELD)) {
268         res.setSPreTasks(retrieveTasks(node));
269       } else if (node.getNodeName().equals(S_POST_TASKS_FIELD)) {
270         res.setSPostTasks(retrieveTasks(node));
271       } else if (node.getNodeName().equals(S_ERROR_TASKS_FIELD)) {
272         res.setSErrorTasks(retrieveTasks(node));
273       }
274     }
275     return res;
276   }
277 
278   private List<String> retrieveHostids(final Node xml)
279       throws DAOConnectionException {
280     final ArrayList<String> res = new ArrayList<String>();
281     if (xml == null || !xml.hasChildNodes()) {
282       return res;
283     }
284     final NodeList hostsList = xml.getChildNodes();
285     for (int i = 0; i < hostsList.getLength(); i++) {
286       res.add(XmlUtil.getExtraTrimed(hostsList.item(i).getTextContent()));
287     }
288     return res;
289   }
290 
291   private List<RuleTask> retrieveTasks(final Node src) {
292     final List<RuleTask> res = new ArrayList<RuleTask>();
293     final NodeList feed = src.getChildNodes();
294     for (int i = 0; i < feed.getLength(); i++) {
295       final Node mainnode = feed.item(i);
296       if (mainnode.getNodeType() == Node.ELEMENT_NODE) {
297         final Element e = (Element) mainnode;
298         final NodeList tasksList = e.getElementsByTagName(TASK_NODE);
299         for (int j = 0; j < tasksList.getLength(); j++) {
300           final Node taskNode = tasksList.item(j);
301           if (taskNode.getNodeType() == Node.ELEMENT_NODE) {
302             final Element task = (Element) taskNode;
303             NodeList nodeList = task.getElementsByTagName(TYPE_FIELD);
304             if (nodeList == null || nodeList.getLength() == 0) {
305               logger.error("Field not found in Rule: " + TYPE_FIELD);
306               continue;
307             }
308             final String type =
309                 XmlUtil.getExtraTrimed(nodeList.item(0).getTextContent());
310             nodeList = task.getElementsByTagName(PATH_FIELD);
311             final String path;
312             if (nodeList != null && nodeList.getLength() > 0) {
313               path = XmlUtil.getExtraTrimed(nodeList.item(0).getTextContent());
314             } else {
315               path = "";
316             }
317             nodeList = task.getElementsByTagName(DELAY_FIELD);
318             final int delay;
319             if (nodeList != null && nodeList.getLength() > 0) {
320               int tmpDelay = 0;
321               try {
322                 tmpDelay = Integer.parseInt(
323                     XmlUtil.getExtraTrimed(nodeList.item(0).getTextContent()));
324               } catch (final NumberFormatException ignored) {
325                 // ignore
326               }
327               delay = tmpDelay;
328             } else {
329               delay = 0;
330             }
331             final RuleTask ruleTask = new RuleTask(type, path, delay);
332             logger.debug("Task {}", ruleTask);
333             res.add(ruleTask);
334           }
335         }
336       }
337     }
338     return res;
339   }
340 }