View Javadoc
1   package org.exoplatform.wiki.service.search.jcr;
2   
3   import org.apache.commons.lang.StringUtils;
4   import org.chromattic.api.NoSuchNodeException;
5   import org.chromattic.api.UndeclaredRepositoryException;
6   import org.exoplatform.container.ExoContainerContext;
7   import org.exoplatform.portal.config.model.PortalConfig;
8   import org.exoplatform.services.jcr.ext.hierarchy.NodeHierarchyCreator;
9   import org.exoplatform.wiki.mow.core.api.wiki.WikiNodeType;
10  import org.exoplatform.wiki.service.search.WikiSearchData;
11  import org.exoplatform.wiki.utils.JCRUtils;
12  import org.exoplatform.wiki.utils.WikiConstants;
13  
14  import javax.jcr.Node;
15  import javax.jcr.PathNotFoundException;
16  import java.util.ArrayList;
17  import java.util.List;
18  
19  /**
20   *
21   */
22  public class JCRWikiSearchQueryBuilder {
23  
24    public static final String ALL_PATH    = "%/";
25  
26    protected static String    PORTAL_PATH = "/exo:applications/"
27            + WikiNodeType.Definition.WIKI_APPLICATION + "/"
28            + WikiNodeType.Definition.WIKIS + "/%/";
29  
30    protected static String    GROUP_PATH  = "/Groups/%/ApplicationData/"
31            + WikiNodeType.Definition.WIKI_APPLICATION + "/";
32  
33    protected String           USER_PATH   = "/Users/%/ApplicationData/" + WikiNodeType.Definition.WIKI_APPLICATION + "/";
34  
35    public static String ALL_PAGESPATH    = ALL_PATH + WikiConstants.WIKI_HOME_NAME;
36  
37    public static String PORTAL_PAGESPATH = PORTAL_PATH + WikiConstants.WIKI_HOME_NAME;
38  
39    public static String GROUP_PAGESPATH  = GROUP_PATH + WikiConstants.WIKI_HOME_NAME;
40  
41    public static String ASC_ORDER = "ASC";
42  
43    public static String DESC_ORDER = "DESC";
44  
45    private WikiSearchData wikiSearchData;
46  
47    private String pagePath = "";
48  
49    protected List<String> propertyConstraints = new ArrayList<>();
50  
51    public JCRWikiSearchQueryBuilder(WikiSearchData wikiSearchData) {
52      this.wikiSearchData = wikiSearchData;
53  
54      if (PortalConfig.USER_TYPE.equals(wikiSearchData.getWikiType())) {
55        NodeHierarchyCreator nodeHierachyCreator = ExoContainerContext.getCurrentContainer().getComponentInstanceOfType(NodeHierarchyCreator.class);
56        try {
57          if (wikiSearchData.getWikiOwner() != null && wikiSearchData.getWikiOwner().length() > 0) {
58            Node userNode = nodeHierachyCreator.getUserApplicationNode(JCRUtils.createSystemProvider(), wikiSearchData.getWikiOwner());
59            USER_PATH = userNode.getPath() + "/" + WikiNodeType.Definition.WIKI_APPLICATION + "/";
60          }
61        } catch (Exception e) {
62          if (e instanceof PathNotFoundException) {
63            throw new NoSuchNodeException(e);
64          } else {
65            throw new UndeclaredRepositoryException(e.getMessage());
66          }
67        }
68      }
69      this.propertyConstraints = new ArrayList<>();
70  
71      initJcrQueryPath();
72    }
73  
74    public List<String> getPropertyConstraints() {
75      return new ArrayList<String>(this.propertyConstraints);
76    }
77  
78    public void addPropertyConstraints(List<String> value) {
79      if (value != null) {
80        propertyConstraints.addAll(value);
81      }
82    }
83  
84    public void addPropertyConstraint(String value) {
85      if (StringUtils.isNotBlank(value)) {
86        propertyConstraints.add(value);
87      }
88    }
89  
90    public void initJcrQueryPath() {
91      if (wikiSearchData.getWikiType() == null && wikiSearchData.getWikiOwner() == null) {
92        pagePath = ALL_PAGESPATH;
93      } else if (wikiSearchData.getWikiType() != null) {
94        if (wikiSearchData.getWikiType().equals(PortalConfig.USER_TYPE)){
95          pagePath = USER_PATH + WikiConstants.WIKI_HOME_NAME;
96        } else {
97          if (wikiSearchData.getWikiType().equals(PortalConfig.PORTAL_TYPE)) {
98            pagePath = PORTAL_PAGESPATH;
99          } else if (wikiSearchData.getWikiType().equals(PortalConfig.GROUP_TYPE)) {
100           pagePath = GROUP_PAGESPATH;
101         }
102 
103         if (wikiSearchData.getWikiOwner() != null && wikiSearchData.getWikiOwner().length() > 0) {
104           pagePath = pagePath.replaceFirst("%", wikiSearchData.getWikiOwner());
105         }
106       }
107     }
108   }
109 
110   public String getStatementForSearchingTitle() {
111     StringBuilder statement = new StringBuilder();
112     statement.append("SELECT title, jcr:primaryType, path, excerpt(.) FROM nt:base WHERE ");
113     statement.append(createJcrQueryPathClause());
114     statement.append(searchTitleCondition());
115     statement.append(createOrderClause());
116     return statement.toString();
117   }
118 
119   public String getStatementForSearchingContent() {
120     StringBuilder statement = new StringBuilder();
121     statement.append("SELECT jcr:primaryType, path, excerpt(.) FROM wiki:attachment WHERE ");
122     statement.append(createJcrQueryPathClause());
123     statement.append(searchContentCondition());
124     statement.append(createOrderClause());
125     return statement.toString();
126   }
127 
128   private String createJcrQueryPathClause() {
129     return "(jcr:path LIKE '" + pagePath + "/%')";
130   }
131 
132   private String createOrderClause() {
133     StringBuffer clause = new StringBuffer();
134     if (isOrderValid(wikiSearchData.getOrder()) && StringUtils.isNotEmpty(wikiSearchData.getSort())) {
135       clause.append(" ORDER BY ");
136       clause.append(wikiSearchData.getSort());
137       clause.append(" ");
138       clause.append(wikiSearchData.getOrder());
139     }
140     return clause.toString();
141   }
142 
143   private boolean isOrderValid(String order) {
144     return ASC_ORDER.equals(order) || DESC_ORDER.equals(order) || "".equals(order);
145   }
146 
147   /**
148    * get SQL constraint for searching available page (be a child of <code>WikiHome</code> page and not removed).
149    * @return
150    *        <ul>
151    *          <li>returned string is in format:
152    *              <code>((jcr:path like [path to page node likely] or jcr:path = [path to page node])
153    *              AND (jcr:mixinTypes IS NULL OR NOT (jcr:mixinTypes = 'wiki:removed'))</code>
154    *          </li>
155    *          <li>
156    *              if <code>wikiType</code> or <code>wikiOwner</code> is null,
157    *              paths of the constraint are <code>/%/pageId</code> and <code>/pageId</code>.
158    *              It means that pages of which id is <code>pageId</code> are searched from <code>root</code>.
159    *          </li>
160    *        </ul>
161    */
162   public String getPageConstraint() {
163     StringBuilder constraint = new StringBuilder();
164 
165     String absPagePath = pagePath + "/" + wikiSearchData.getPageId();
166     String pageLikePath = pagePath + "/%/" + wikiSearchData.getPageId();
167     boolean isWikiHome = false;
168     if (WikiConstants.WIKI_HOME_NAME.equals(wikiSearchData.getPageId())) {
169       absPagePath = pagePath;
170       isWikiHome = true;
171     }
172     if (wikiSearchData.getWikiType() == null || wikiSearchData.getWikiOwner() == null) {
173       absPagePath = "/" + wikiSearchData.getPageId();
174       pageLikePath = "/%/" + wikiSearchData.getPageId();
175     }
176     constraint.append('(').append('(').append("jcr:path LIKE '").append(pageLikePath).append('\'');
177     if (!isWikiHome)
178       constraint.append(" or (jcr:path = '").append(absPagePath).append('\'').append(')');
179     constraint.append(")")
180             .append(" AND ")
181             .append("(jcr:mixinTypes IS NULL OR NOT (jcr:mixinTypes = 'wiki:removed'))")
182             .append(')');
183     return constraint.toString();
184   }
185 
186   private String searchContentCondition() {
187     StringBuilder clause = new StringBuilder();
188     if (wikiSearchData.getContent() != null && wikiSearchData.getContent().length() > 0 && !"*".equals(wikiSearchData.getContent())) {
189       clause.append(" AND ");
190       clause.append(" CONTAINS(*, '").append(wikiSearchData.getContent()).append("')");
191     }
192     return clause.toString();
193   }
194 
195   private String searchTitleCondition() {
196     StringBuilder clause = new StringBuilder();
197     if (wikiSearchData.getTitle() != null && wikiSearchData.getTitle().length() > 0) {
198       clause.append(" AND ");
199       clause.append(" CONTAINS(title, '").append(wikiSearchData.getTitle()).append("')");
200     }
201     return clause.toString();
202   }
203 
204 }