1 package org
.argeo
.suite
.util
;
3 import java
.text
.DateFormat
;
4 import java
.text
.SimpleDateFormat
;
5 import java
.util
.Calendar
;
7 import javax
.jcr
.RepositoryException
;
8 import javax
.jcr
.Session
;
9 import javax
.jcr
.query
.Query
;
10 import javax
.jcr
.query
.QueryManager
;
12 import org
.apache
.commons
.logging
.Log
;
13 import org
.apache
.commons
.logging
.LogFactory
;
14 import org
.apache
.jackrabbit
.util
.ISO9075
;
16 /** Ease XPath generation for JCR requests */
17 public class XPathUtils
{
18 private final static Log log
= LogFactory
.getLog(XPathUtils
.class);
20 private final static String QUERY_XPATH
= "xpath";
22 public static String
descendantFrom(String parentPath
) {
23 if (notEmpty(parentPath
)) {
24 if ("/".equals(parentPath
))
26 // Hardcoded dependency to Jackrabbit. Remove
27 String result
= "/jcr:root" + ISO9075
.encodePath(parentPath
);
28 if (log
.isTraceEnabled()) {
29 String result2
= "/jcr:root" + parentPath
;
30 if (!result2
.equals(result
))
31 log
.warn("Encoded Path " + result2
+ " --> " + result
);
38 public static String
localAnd(String
... conditions
) {
39 StringBuilder builder
= new StringBuilder();
40 for (String condition
: conditions
) {
41 if (notEmpty(condition
)) {
42 builder
.append(" ").append(condition
).append(" and ");
45 if (builder
.length() > 3)
46 return builder
.substring(0, builder
.length() - 4);
51 public static String
xPathNot(String condition
) {
52 if (notEmpty(condition
))
53 return "not(" + condition
+ ")";
58 public static String
getFreeTextConstraint(String filter
) throws RepositoryException
{
59 StringBuilder builder
= new StringBuilder();
60 if (notEmpty(filter
)) {
61 String
[] strs
= filter
.trim().split(" ");
62 for (String token
: strs
) {
63 builder
.append("jcr:contains(.,'*" + encodeXPathStringValue(token
) + "*') and ");
65 return builder
.substring(0, builder
.length() - 4);
70 public static String
getPropertyContains(String propertyName
, String filter
) throws RepositoryException
{
72 return "jcr:contains(@" + propertyName
+ ",'*" + encodeXPathStringValue(filter
) + "*')";
76 private final static DateFormat jcrRefFormatter
= new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
80 * @param calendar the reference date
81 * @param lowerOrGreater "<", ">" TODO validate ">="
83 * @throws RepositoryException
85 public static String
getPropertyDateComparaison(String propertyName
, Calendar cal
, String lowerOrGreater
)
86 throws RepositoryException
{
88 String jcrDateStr
= jcrRefFormatter
.format(cal
.getTime());
90 // jcrDateStr = "2015-08-03T05:00:03:000Z";
91 String result
= "@" + propertyName
+ " " + lowerOrGreater
+ " xs:dateTime('" + jcrDateStr
+ "')";
97 public static String
getPropertyEquals(String propertyName
, String value
) {
99 return "@" + propertyName
+ "='" + encodeXPathStringValue(value
) + "'";
103 public static String
encodeXPathStringValue(String propertyValue
) {
104 // TODO implement safer mechanism to escape invalid characters
105 // Also check why we have used this regex in ResourceSerrviceImpl l 474
106 // String cleanedKey = key.replaceAll("(?:')", "''");
107 String result
= propertyValue
.replaceAll("'", "''");
111 public static void andAppend(StringBuilder builder
, String condition
) {
112 if (notEmpty(condition
)) {
113 builder
.append(condition
);
114 builder
.append(" and ");
118 public static void appendOrderByProperties(StringBuilder builder
, boolean ascending
, String
... propertyNames
) {
119 if (propertyNames
.length
> 0) {
120 builder
.append(" order by ");
121 for (String propName
: propertyNames
)
122 builder
.append("@").append(propName
).append(", ");
123 builder
= builder
.delete(builder
.length() - 2, builder
.length());
125 builder
.append(" ascending ");
127 builder
.append(" descending ");
131 public static void appendAndPropStringCondition(StringBuilder builder
, String propertyName
, String filter
)
132 throws RepositoryException
{
133 if (notEmpty(filter
)) {
134 andAppend(builder
, getPropertyContains(propertyName
, filter
));
138 public static void appendAndNotPropStringCondition(StringBuilder builder
, String propertyName
, String filter
)
139 throws RepositoryException
{
140 if (notEmpty(filter
)) {
141 String cond
= getPropertyContains(propertyName
, filter
);
142 builder
.append(xPathNot(cond
));
143 builder
.append(" and ");
147 public static Query
createQuery(Session session
, String queryString
) throws RepositoryException
{
148 QueryManager queryManager
= session
.getWorkspace().getQueryManager();
149 // Localise JCR properties for XPATH
150 queryString
= localiseJcrItemNames(queryString
);
151 return queryManager
.createQuery(queryString
, QUERY_XPATH
);
154 private final static String NS_JCR
= "\\{http://www.jcp.org/jcr/1.0\\}";
155 private final static String NS_NT
= "\\{http://www.jcp.org/jcr/nt/1.0\\}";
156 private final static String NS_MIX
= "\\{http://www.jcp.org/jcr/mix/1.0\\}";
159 * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
160 * is a workaround that must be later cleaned
162 public static String
localiseJcrItemNames(String name
) {
163 name
= name
.replaceAll(NS_JCR
, "jcr:");
164 name
= name
.replaceAll(NS_NT
, "nt:");
165 name
= name
.replaceAll(NS_MIX
, "mix:");
169 private static boolean notEmpty(String stringToTest
) {
170 return !(stringToTest
== null || "".equals(stringToTest
.trim()));
174 private XPathUtils() {