View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.frontend.xeditor.jaxen;
20  
21  import java.lang.reflect.Field;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.apache.logging.log4j.LogManager;
27  import org.apache.logging.log4j.Logger;
28  import org.jaxen.Function;
29  import org.jaxen.XPath;
30  import org.jaxen.XPathFunctionContext;
31  import org.jdom2.Namespace;
32  import org.jdom2.filter.Filter;
33  import org.jdom2.xpath.XPathExpression;
34  import org.jdom2.xpath.jaxen.JaxenXPathFactory;
35  import org.mycore.common.MCRConstants;
36  
37  /**
38   * @author Frank L├╝tzenkirchen
39   */
40  public class MCRJaxenXPathFactory extends JaxenXPathFactory {
41  
42      private static final Logger LOGGER = LogManager.getLogger(MCRJaxenXPathFactory.class);
43  
44      private List<ExtensionFunction> functions = new ArrayList<>();
45  
46      public MCRJaxenXPathFactory() {
47          super();
48          functions.add(new ExtensionFunction("xed", "generate-id", new MCRFunctionGenerateID()));
49          functions.add(new ExtensionFunction("xed", "call-java", new MCRFunctionCallJava()));
50          functions.add(new ExtensionFunction("i18n", "translate", new MCRFunctionTranslate()));
51      }
52  
53      @Override
54      public <T> XPathExpression<T> compile(String expression, Filter<T> filter, Map<String, Object> variables,
55          Namespace... namespaces) {
56          XPathExpression<T> jaxenCompiled = super.compile(expression, filter, variables, namespaces);
57  
58          if (functions.stream().anyMatch(function -> function.isCalledIn(expression))) {
59              addExtensionFunctions(jaxenCompiled, namespaces);
60          }
61          return jaxenCompiled;
62      }
63  
64      private <T> void addExtensionFunctions(XPathExpression<T> jaxenCompiled, Namespace... namespaces) {
65          try {
66              XPath xPath = getXPath(jaxenCompiled);
67              addExtensionFunctions(xPath);
68          } catch (Exception ex) {
69              LOGGER.warn(ex);
70          }
71      }
72  
73      private void addExtensionFunctions(XPath xPath) {
74          XPathFunctionContext xfc = (XPathFunctionContext) (xPath.getFunctionContext());
75          for (ExtensionFunction function : functions)
76              function.register(xfc);
77          xPath.setFunctionContext(xfc);
78      }
79  
80      private <T> XPath getXPath(XPathExpression<T> jaxenCompiled) throws NoSuchFieldException, IllegalAccessException {
81          Field xPathField = jaxenCompiled.getClass().getDeclaredField("xPath");
82          xPathField.setAccessible(true);
83          XPath xPath = (XPath) (xPathField.get(jaxenCompiled));
84          xPathField.setAccessible(false);
85          return xPath;
86      }
87  
88      class ExtensionFunction {
89  
90          String prefix;
91  
92          String localName;
93  
94          Function function;
95  
96          public ExtensionFunction(String prefix, String localName, Function function) {
97              this.prefix = prefix;
98              this.localName = localName;
99              this.function = function;
100         }
101 
102         public void register(XPathFunctionContext context) {
103             context.registerFunction(MCRConstants.getStandardNamespace(prefix).getURI(), localName, function);
104         }
105 
106         public boolean isCalledIn(String xPathExpression) {
107             return xPathExpression.contains(prefix + ":" + localName + "(");
108         }
109     }
110 }