1 package org
.argeo
.app
.jcr
;
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
.jackrabbit
.util
.ISO9075
;
13 import org
.argeo
.api
.cms
.CmsLog
;
15 /** Ease XPath generation for JCR requests */
16 public class XPathUtils
{
17 private final static CmsLog log
= CmsLog
.getLog(XPathUtils
.class);
19 private final static String QUERY_XPATH
= "xpath";
21 public static String
descendantFrom(String parentPath
) {
22 if (notEmpty(parentPath
)) {
23 if ("/".equals(parentPath
))
25 // Hardcoded dependency to Jackrabbit. Remove
26 String result
= "/jcr:root" + ISO9075
.encodePath(parentPath
);
27 if (log
.isTraceEnabled()) {
28 String result2
= "/jcr:root" + parentPath
;
29 if (!result2
.equals(result
))
30 log
.warn("Encoded Path " + result2
+ " --> " + result
);
37 public static String
localAnd(String
... conditions
) {
38 StringBuilder builder
= new StringBuilder();
39 for (String condition
: conditions
) {
40 if (notEmpty(condition
)) {
41 builder
.append(" ").append(condition
).append(" and ");
44 if (builder
.length() > 3)
45 return builder
.substring(0, builder
.length() - 4);
50 public static String
xPathNot(String condition
) {
51 if (notEmpty(condition
))
52 return "not(" + condition
+ ")";
57 public static String
getFreeTextConstraint(String filter
) throws RepositoryException
{
58 StringBuilder builder
= new StringBuilder();
59 if (notEmpty(filter
)) {
60 String
[] strs
= filter
.trim().split(" ");
61 for (String token
: strs
) {
62 builder
.append("jcr:contains(.,'*" + encodeXPathStringValue(token
) + "*') and ");
64 return builder
.substring(0, builder
.length() - 4);
69 public static String
getPropertyContains(String propertyName
, String filter
) throws RepositoryException
{
71 return "jcr:contains(@" + propertyName
+ ",'*" + encodeXPathStringValue(filter
) + "*')";
75 private final static DateFormat jcrRefFormatter
= new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSS'+02:00'");
79 * @param calendar the reference date
80 * @param lowerOrGreater "<", ">" TODO validate ">="
81 * @throws RepositoryException
83 public static String
getPropertyDateComparaison(String propertyName
, Calendar cal
, String lowerOrGreater
)
84 throws RepositoryException
{
86 String jcrDateStr
= jcrRefFormatter
.format(cal
.getTime());
88 // jcrDateStr = "2015-08-03T05:00:03:000Z";
89 String result
= "@" + propertyName
+ " " + lowerOrGreater
+ " xs:dateTime('" + jcrDateStr
+ "')";
95 public static String
getPropertyEquals(String propertyName
, String value
) {
97 return "@" + propertyName
+ "='" + encodeXPathStringValue(value
) + "'";
101 public static String
encodeXPathStringValue(String propertyValue
) {
102 // TODO implement safer mechanism to escape invalid characters
103 // Also check why we have used this regex in ResourceSerrviceImpl l 474
104 // String cleanedKey = key.replaceAll("(?:')", "''");
105 String result
= propertyValue
.replaceAll("'", "''");
109 public static void andAppend(StringBuilder builder
, String condition
) {
110 if (notEmpty(condition
)) {
111 builder
.append(condition
);
112 builder
.append(" and ");
116 public static void appendOrderByProperties(StringBuilder builder
, boolean ascending
, String
... propertyNames
) {
117 if (propertyNames
.length
> 0) {
118 builder
.append(" order by ");
119 for (String propName
: propertyNames
)
120 builder
.append("@").append(propName
).append(", ");
121 builder
= builder
.delete(builder
.length() - 2, builder
.length());
123 builder
.append(" ascending ");
125 builder
.append(" descending ");
129 public static void appendAndPropStringCondition(StringBuilder builder
, String propertyName
, String filter
)
130 throws RepositoryException
{
131 if (notEmpty(filter
)) {
132 andAppend(builder
, getPropertyContains(propertyName
, filter
));
136 public static void appendAndNotPropStringCondition(StringBuilder builder
, String propertyName
, String filter
)
137 throws RepositoryException
{
138 if (notEmpty(filter
)) {
139 String cond
= getPropertyContains(propertyName
, filter
);
140 builder
.append(xPathNot(cond
));
141 builder
.append(" and ");
145 public static Query
createQuery(Session session
, String queryString
) throws RepositoryException
{
146 QueryManager queryManager
= session
.getWorkspace().getQueryManager();
147 // Localise JCR properties for XPATH
148 queryString
= localiseJcrItemNames(queryString
);
149 return queryManager
.createQuery(queryString
, QUERY_XPATH
);
152 private final static String NS_JCR
= "\\{http://www.jcp.org/jcr/1.0\\}";
153 private final static String NS_NT
= "\\{http://www.jcp.org/jcr/nt/1.0\\}";
154 private final static String NS_MIX
= "\\{http://www.jcp.org/jcr/mix/1.0\\}";
157 * Replace the generic namespace with the local "jcr:", "nt:", "mix:" values. It
158 * is a workaround that must be later cleaned
160 public static String
localiseJcrItemNames(String name
) {
161 name
= name
.replaceAll(NS_JCR
, "jcr:");
162 name
= name
.replaceAll(NS_NT
, "nt:");
163 name
= name
.replaceAll(NS_MIX
, "mix:");
167 private static boolean notEmpty(String stringToTest
) {
168 return !(stringToTest
== null || "".equals(stringToTest
.trim()));
172 private XPathUtils() {