/*
* Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wso2.carbon.registry.search.services.utils;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.config.StaticConfiguration;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.core.utils.RegistryUtils;
import static org.wso2.carbon.utils.CarbonUtils.getMD5;
/**
* Represents an advanced query on normal resources. Handles all details of defining, executing and
* parameter processing of such queries.
*/
public class AdvancedResourceQuery {
private static Log log = LogFactory.getLog(AdvancedResourceQuery.class);
/**
* List of parameters for the query. NOTE THAT THIS LIST SHOULD ALWAYS BE PROCESSED IN THE ORDER
* THEY ARE LISTED BELOW.
*/
private String resourceName;
private String authorName;
private String updaterName;
private String commentWords;
private String propertyName;
private String propertyValue;
private String content;
private Map<String, String> customSearchValues;
private String mediaType;
private Set<String> tags;
private String queryPath;
private long createdAfter = Long.MIN_VALUE;
private long createdBefore = Long.MIN_VALUE;
private long updatedAfter = Long.MIN_VALUE;
private long updatedBefore = Long.MIN_VALUE;
public Resource execute(Registry configSystemRegistry, Registry registry) throws RegistryException {
// find if query is already defined
// if defined, execute
// else, create new query and execute
// if the registry is in read-only mode, and the query is not available on the registry,
// it will be passed in as a parameter.
String queryPath = computeQueryPathPrefix();
if (queryPath.indexOf("1") == -1 && queryPath.indexOf("T") == -1) {
String msg = "No parameters are specified for the query.";
log.error(msg);
throw new RegistryException(msg);
}
String query = null;
String resourceQueryPath = queryPath + "r";
// if (!queryExists(configSystemRegistry, resourceQueryPath)) {
String queryResourceContent = generateSQLForResources();
if (queryResourceContent != null) {
// this part has been commented to fix the search issue in stratos
// if (!RegistryUtils.isRegistryReadOnly(configSystemRegistry.getRegistryContext())) {
// defineQueries(configSystemRegistry, resourceQueryPath, queryResourceContent);
// } else {
// log.debug("Running Query in READ-ONLY mode.");
query = queryResourceContent;
// }
}
// }
String[] resourcePaths = executeResourceQuery(registry,
RegistryConstants.CONFIG_REGISTRY_BASE_PATH + resourceQueryPath, query);
String[] collectionPaths = new String[0];
query = null;
String collectionQueryPath = queryPath + "c";
String queryCollectionContent = generateSQLForCollections();
if (queryCollectionContent != null) {
// this part has been commented to fix the search issue in stratos
// if (!RegistryUtils.isRegistryReadOnly(configSystemRegistry.getRegistryContext())) {
// defineQueries(configSystemRegistry, collectionQueryPath, queryCollectionContent);
// } else {
// log.debug("Running Query in READ-ONLY mode.");
query = queryCollectionContent;
// }
collectionPaths = executeCollectionQuery(registry,
RegistryConstants.CONFIG_REGISTRY_BASE_PATH + collectionQueryPath, query);
}
ArrayList<String> totalPathsArr = new ArrayList<String>();
HashMap<String, Integer> resourceKeyHash = new HashMap<String, Integer>();
for (int i = 0; i < resourcePaths.length; i++) {
totalPathsArr.add(resourcePaths[i]);
resourceKeyHash.put(resourcePaths[i], 1);
}
for (int i = 0; i < collectionPaths.length; i++) {
if (resourceKeyHash.containsKey(collectionPaths[i])) {
// is a resource
continue;
}
totalPathsArr.add(collectionPaths[i]);
}
String[] totalPaths = totalPathsArr.toArray(new String[totalPathsArr.size()]);
Collection c = registry.newCollection();
c.setContent(totalPaths);
query = null;
this.queryPath = null;
return c;
}
private String[] executeResourceQuery(Registry registry, String queryPath, String query)
throws RegistryException {
List<Object> params = new ArrayList<Object>();
if (resourceName != null && resourceName.length() != 0) {
params.add(resourceName);
}
if (authorName != null && authorName.length() != 0) {
params.add("%"+authorName+"%");
}
if (updaterName != null && updaterName.length() != 0) {
params.add("%"+updaterName+"%");
}
if (createdAfter > Long.MIN_VALUE) {
params.add(new Timestamp(createdAfter));
}
if (createdBefore > Long.MIN_VALUE) {
params.add(new Timestamp(createdBefore));
}
if (updatedAfter > Long.MIN_VALUE) {
params.add(new Timestamp(updatedAfter));
}
if (updatedBefore > Long.MIN_VALUE) {
params.add(new Timestamp(updatedBefore));
}
if (commentWords != null && commentWords.length() != 0) {
params.add("%" + commentWords + "%");
}
if (tags != null && !tags.isEmpty()) {
params.addAll(tags);
}
if (propertyName != null) {
params.add(propertyName);
}
if (propertyValue != null) {
params.add(propertyValue);
}
if(mediaType != null){
params.add(mediaType);
}
if (customSearchValues.size() > 0) {
Iterator<String> it = customSearchValues.keySet().iterator();
while (it.hasNext()) {
String s = it.next();
if (!customSearchValues.get(s).trim().equals("")) {
params.add(customSearchValues.get(s));
}
}
}
Map paramMap = new HashMap();
for (int i = 0; i < params.size(); i++) {
Object value = params.get(i);
paramMap.put(Integer.toString(i + 1), value);
}
if (content != null) {
paramMap.put("content", content);
}
Resource r;
if (query != null && query.length() != 0) {
paramMap.put("query", query);
r = registry.executeQuery(null, paramMap);
} else {
r = registry.executeQuery(queryPath, paramMap);
}
return (String[]) r.getContent();
}
private String[] executeCollectionQuery
(Registry
registry, String
queryPath, String
query)
throws RegistryException {
List<Object> params = new ArrayList<Object>();
if (resourceName != null && resourceName.length() != 0) {
params.add("%/" + resourceName);
params.add("%/" + resourceName + "/%");
}
if (authorName != null && authorName.length() != 0) {
params.add("%"+authorName+"%");
}
if (updaterName != null && updaterName.length() != 0) {
params.add("%"+updaterName+"%");
}
if (createdAfter > Long.MIN_VALUE) {
params.add(new Timestamp(createdAfter));
}
if (createdBefore > Long.MIN_VALUE) {
params.add(new Timestamp(createdBefore));
}
if (updatedAfter > Long.MIN_VALUE) {
params.add(new Timestamp(updatedAfter));
}
if (updatedBefore > Long.MIN_VALUE) {
params.add(new Timestamp(updatedBefore));
}
if (commentWords != null && commentWords.length() != 0) {
params.add("%" + commentWords + "%");
}
if (tags != null && !tags.isEmpty()) {
params.addAll(tags);
}
if (propertyName != null) {
params.add(propertyName);
}
if (propertyValue != null) {
params.add(propertyValue);
}
if(mediaType != null){
params.add(mediaType);
}
if (customSearchValues.size() > 0) {
Iterator<String> it = customSearchValues.keySet().iterator();
while (it.hasNext()) {
String s = it.next();
if (!customSearchValues.get(s).trim().equals("")) {
params.add(customSearchValues.get(s));
}
}
}
Map paramMap = new HashMap();
for (int i = 0; i < params.size(); i++) {
Object value = params.get(i);
paramMap.put(Integer.toString(i + 1), value);
}
if (content != null) {
paramMap.put("content", content);
}
Resource r;
if (query != null && query.length() != 0) {
paramMap.put("query", query);
r = registry.executeQuery(null, paramMap);
} else {
r = registry.executeQuery(queryPath, paramMap);
}
return (String[]) r.getContent();
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
if ("".equals(resourceName)) resourceName = null;
if (resourceName != null) {
resourceName = resourceName.toLowerCase();
}
this.resourceName = resourceName;
}
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
if ("".equals(authorName)) authorName = null;
this.authorName = authorName;
}
public String getUpdaterName() {
return updaterName;
}
public void setUpdaterName(String updaterName) {
if ("".equals(updaterName)) updaterName = null;
this.updaterName = updaterName;
}
public Date getCreatedAfter() {
return (createdAfter == Long.MIN_VALUE) ? null : new Date(createdAfter);
}
public void setCreatedAfter(Date createdAfter) {
this.createdAfter = (createdAfter == null) ? Long.MIN_VALUE : createdAfter.getTime();
}
public Date getCreatedBefore() {
return (createdBefore == Long.MIN_VALUE) ? null : new Date(createdBefore);
}
public void setCreatedBefore(Date createdBefore) {
this.createdBefore = (createdBefore == null) ? Long.MIN_VALUE : createdBefore.getTime();
}
public Date getUpdatedAfter() {
return (updatedAfter == Long.MIN_VALUE) ? null : new Date(updatedAfter);
}
public void setUpdatedAfter(Date updatedAfter) {
this.updatedAfter = (updatedAfter == null) ? Long.MIN_VALUE : updatedAfter.getTime();
}
public Date getUpdatedBefore() {
return (updatedBefore == Long.MIN_VALUE) ? null : new Date(updatedBefore);
}
public void setUpdatedBefore(Date updatedBefore) {
this.updatedBefore = (updatedBefore == null) ? Long.MIN_VALUE : updatedBefore.getTime();
}
public void setTags(String tags) {
this.tags = parseTags(tags);
}
public void setPropertyName(String propertyName) {
if ("".equals(propertyName)) propertyName = null;
this.propertyName = propertyName;
}
public void setPropertyValue(String propertyValue) {
if ("".equals(propertyValue)) propertyValue = null;
this.propertyValue = propertyValue;
}
public String getCommentWords() {
return commentWords;
}
public void setCommentWords(String commentWords) {
if ("".equals(commentWords)) commentWords = null;
this.commentWords = commentWords;
}
public String getContent() {
return this.content;
}
public void setContent(String content) {
this.content = content;
}
public Map<String, String> getCustomSearchValues() {
return customSearchValues;
}
public void setCustomSearchValues(Map<String, String> customSearchValues) {
this.customSearchValues = customSearchValues;
}
public String getMediaType() {
return mediaType;
}
public void setMediaType(String mediaType) {
if ("".equals(mediaType)) mediaType = null;
this.mediaType = mediaType;
}
private boolean queryExists(Registry configSystemRegistry, String queryPath) throws RegistryException {
UserRegistry registry = (UserRegistry) configSystemRegistry;
return registry.resourceExists(queryPath);
}
private void defineQueries(Registry configSystemRegistry, String queryPath, String queryContent) throws RegistryException {
UserRegistry registry =
(UserRegistry) configSystemRegistry;
Resource q1 = registry.newResource();
q1.setContent(queryContent);
q1.setMediaType(RegistryConstants.SQL_QUERY_MEDIA_TYPE);
q1.addProperty(RegistryConstants.RESULT_TYPE_PROPERTY_NAME,
RegistryConstants.RESOURCES_RESULT_TYPE);
registry.put(queryPath, q1);
}
private String computeQueryPathPrefix() {
if (queryPath == null) {
StringBuffer buf = new StringBuffer(RegistryConstants.QUERIES_COLLECTION_PATH + "/advanced");
buf.append(resourceName != null ? "1" : "0");
buf.append(authorName != null ? "1" : "0");
buf.append(updaterName != null ? "1" : "0");
buf.append(createdAfter > Long.MIN_VALUE ? "1" : "0");
buf.append(createdBefore > Long.MIN_VALUE ? "1" : "0");
buf.append(updatedAfter > Long.MIN_VALUE ? "1" : "0");
buf.append(updatedBefore > Long.MIN_VALUE ? "1" : "0");
buf.append(commentWords != null ? "1" : "0");
buf.append(propertyName != null ? "1" : "0");
buf.append(propertyValue != null ? "1" : "0");
buf.append(mediaType != null ? "1" : "0");
if (tags != null) {
buf.append("T");
buf.append(tags.size());
}
if (customSearchValues.size() > 0) {
StringBuffer fileName = new StringBuffer();
for (Map.Entry<String, String> e : customSearchValues.entrySet()) {
if (!e.getValue().trim().equals("")) {
fileName.append(e.getKey());
}
}
buf.append(getMD5(fileName.toString().getBytes()));
}
// Iterator<String> it = customSearchValues.keySet().iterator();
// buf.append("P");
//
//
//
// while (it.hasNext()) {
// String s = it.next();
// if (!customSearchValues.get(s).trim().equals("")) {
// buf.append("1");
// } else {
// buf.append("0");
// }
// }
queryPath = buf.toString();
}
return queryPath;
}
public Set<String> parseTags
(String
tags) {
Set<String> result = new HashSet<String>();
String[] parts = tags.split("\\,");
for (String part1 : parts) {
String part = part1.trim();
if (!"".equals(part)) {
result.add(part);
}
}
return result;
}
// get sql queries to search resources
private String generateSQLForResources
() {
ArrayList<String> tables = new ArrayList<String>();
ArrayList<String> conditions = new ArrayList<String>();
if (resourceName != null && resourceName.length() != 0) {
conditions.add("lower(R.REG_NAME) LIKE ?");
}
if (authorName != null && authorName.length() != 0) {
conditions.add("R.REG_CREATOR LIKE ?");
}
if (updaterName != null && updaterName.length() != 0) {
conditions.add("R.REG_LAST_UPDATOR LIKE ?");
}
if (createdAfter > Long.MIN_VALUE) {
conditions.add("R.REG_CREATED_TIME > ?");
}
if (createdBefore > Long.MIN_VALUE) {
conditions.add("R.REG_CREATED_TIME < ?");
}
if (updatedAfter > Long.MIN_VALUE) {
conditions.add("R.REG_LAST_UPDATED_TIME > ?");
}
if (updatedBefore > Long.MIN_VALUE) {
conditions.add("R.REG_LAST_UPDATED_TIME < ?");
}
if (commentWords != null && commentWords.length() != 0) {
tables.add(", REG_COMMENT C");
tables.add(", REG_RESOURCE_COMMENT RC");
if (StaticConfiguration.isVersioningComments()) {
conditions.add("R.REG_VERSION=RC.REG_VERSION AND RC.REG_COMMENT_ID=C.REG_ID AND " +
"C.REG_COMMENT_TEXT LIKE ?");
} else {
conditions.add("R.REG_PATH_ID=RC.REG_PATH_ID AND " +
"((R.REG_NAME = RC.REG_RESOURCE_NAME)) AND " +
"RC.REG_COMMENT_ID=C.REG_ID AND " +
"C.REG_COMMENT_TEXT LIKE ?");
}
}
if (tags != null && !tags.isEmpty()) {
tables.add(", REG_TAG T");
tables.add(", REG_RESOURCE_TAG RT");
StringBuffer tagClause = new StringBuffer();
if (StaticConfiguration.isVersioningTags()) {
tagClause.append("R.REG_VERSION=RT.REG_VERSION AND " +
"RT.REG_TAG_ID=T.REG_ID ");
} else {
tagClause.append("R.REG_PATH_ID=RT.REG_PATH_ID AND " +
"((R.REG_NAME = RT.REG_RESOURCE_NAME)) AND " +
"RT.REG_TAG_ID=T.REG_ID ");
}
Iterator<String> i = tags.iterator();
int count = 0;
while (i.hasNext()) {
count++;
if (count == 1) {
tagClause.append(" AND (lower(T.REG_TAG_NAME)=lower(?)");
} else {
tagClause.append(" OR lower(T.REG_TAG_NAME)=lower(?)");
}
i.next();
}
if (tags.size() > 0) {
tagClause.append(")");
}
conditions.add(tagClause.toString());
}
boolean bool = false;
if (customSearchValues.size() > 0) {
for (Map.Entry<String, String> e : customSearchValues.entrySet()) {
if (!e.getValue().trim().equals("")) {
bool = true;
}
}
}
if (bool || propertyValue != null || propertyName != null) {
tables.add(", REG_PROPERTY PP");
tables.add(", REG_RESOURCE_PROPERTY RP");
// StringBuffer propertyClause = new StringBuffer();
if (StaticConfiguration.isVersioningProperties()) {
conditions.add("R.REG_VERSION=RP.REG_VERSION AND " +
"RP.REG_PROPERTY_ID=PP.REG_ID");
} else {
conditions.add("R.REG_PATH_ID=RP.REG_PATH_ID AND " +
"((R.REG_NAME = RP.REG_RESOURCE_NAME)) AND " +
"RP.REG_PROPERTY_ID=PP.REG_ID");
}
}
if (propertyValue != null || propertyName != null) {
// StringBuffer propertyClause = new StringBuffer();
if (propertyName != null) {
conditions.add(" lower(PP.REG_NAME)=lower(?)");
}
if (propertyValue != null) {
conditions.add(" PP.REG_VALUE LIKE ?");
}
}
if(mediaType != null){
conditions.add("R.REG_MEDIA_TYPE LIKE ?");
}
if (customSearchValues.size() > 0) {
StringBuffer propertyClause = new StringBuffer();
boolean firstTime = true;
for (Map.Entry<String, String> e : customSearchValues.entrySet()) {
if (!e.getValue().trim().equals("")) {
if (firstTime) {
propertyClause.append(" lower(PP.REG_NAME)=lower(\'").append(e.getKey()).append("\')")
.append(" AND PP.REG_VALUE LIKE ?");
firstTime = false;
} else {
propertyClause.append(" AND lower(PP.REG_NAME)=lower(\'").append(e.getKey()).append("\')")
.append(" AND PP.REG_VALUE LIKE ?");
}
}
}
if (!(propertyClause.toString().equals(""))) {
conditions.add(propertyClause.toString());
}
}
StringBuffer query = new StringBuffer();
query.append("SELECT R.REG_PATH_ID, R.REG_NAME FROM REG_RESOURCE R");
for (String table : tables) {
query.append(table);
}
boolean first = true;
for (String condition : conditions) {
if (first) {
query.append(" WHERE ");
first = false;
} else {
query.append(" AND ");
}
query.append(condition);
}
return query.toString();
}
// sql specific to collections
private String generateSQLForCollections
() {
ArrayList<String> tables = new ArrayList<String>();
ArrayList<String> conditions = new ArrayList<String>();
conditions.add("R.REG_NAME IS NULL");
if (resourceName != null && resourceName.length() != 0) {
tables.add(", REG_PATH P");
conditions.add(" lower(P.REG_PATH_VALUE) LIKE ? AND lower(P.REG_PATH_VALUE) NOT LIKE " +
"? AND P.REG_PATH_ID=R.REG_PATH_ID");
}
if (authorName != null && authorName.length() != 0) {
conditions.add("R.REG_CREATOR LIKE ?");
}
if (updaterName != null && updaterName.length() != 0) {
conditions.add("R.REG_LAST_UPDATOR LIKE ?");
}
if (createdAfter > Long.MIN_VALUE) {
conditions.add("R.REG_CREATED_TIME > ?");
}
if (createdBefore > Long.MIN_VALUE) {
conditions.add("R.REG_CREATED_TIME < ?");
}
if (updatedAfter > Long.MIN_VALUE) {
conditions.add("R.REG_LAST_UPDATED_TIME > ?");
}
if (updatedBefore > Long.MIN_VALUE) {
conditions.add("R.REG_LAST_UPDATED_TIME < ?");
}
if (commentWords != null && commentWords.length() != 0) {
tables.add(", REG_COMMENT C");
tables.add(", REG_RESOURCE_COMMENT RC");
if (StaticConfiguration.isVersioningComments()) {
conditions.add("R.REG_VERSION=RC.REG_VERSION AND RC.REG_COMMENT_ID=C.REG_ID AND " +
"C.REG_COMMENT_TEXT LIKE ?");
} else {
conditions.add("R.REG_PATH_ID=RC.REG_PATH_ID AND " +
"R.REG_NAME IS NULL AND RC.REG_RESOURCE_NAME IS NULL AND " +
"RC.REG_COMMENT_ID=C.REG_ID AND " +
"C.REG_COMMENT_TEXT LIKE ?");
}
}
if (tags != null && !tags.isEmpty()) {
tables.add(", REG_TAG T");
tables.add(", REG_RESOURCE_TAG RT");
StringBuffer tagClause = new StringBuffer();
if (StaticConfiguration.isVersioningTags()) {
tagClause.append("R.REG_VERSION=RT.REG_VERSION AND " +
"RT.REG_TAG_ID=T.REG_ID ");
} else {
tagClause.append("R.REG_PATH_ID=RT.REG_PATH_ID AND " +
"R.REG_NAME IS NULL AND RT.REG_RESOURCE_NAME IS NULL AND " +
"RT.REG_TAG_ID=T.REG_ID ");
}
Iterator<String> i = tags.iterator();
int count = 0;
while (i.hasNext()) {
count++;
if (count == 1) {
tagClause.append(" AND (lower(T.REG_TAG_NAME)=lower(?)");
} else {
tagClause.append(" OR lower(T.REG_TAG_NAME)=lower(?)");
}
i.next();
}
if (tags.size() > 0) {
tagClause.append(")");
}
conditions.add(tagClause.toString());
}
boolean bool = false;
if (customSearchValues.size() > 0) {
for (Map.Entry<String, String> e : customSearchValues.entrySet()) {
if (!e.getValue().trim().equals("")) {
bool = true;
}
}
}
if (bool || propertyValue != null || propertyName != null) {
tables.add(", REG_PROPERTY PP");
tables.add(", REG_RESOURCE_PROPERTY RP");
if (StaticConfiguration.isVersioningProperties()) {
conditions.add("R.REG_VERSION=RP.REG_VERSION AND " +
"RP.REG_PROPERTY_ID=PP.REG_ID");
} else {
conditions.add("R.REG_PATH_ID=RP.REG_PATH_ID AND " +
"R.REG_NAME IS NULL AND RP.REG_RESOURCE_NAME IS NULL AND " +
"RP.REG_PROPERTY_ID=PP.REG_ID");
}
}
if (propertyValue != null || propertyName != null) {
StringBuffer propertyClause = new StringBuffer();
if (propertyName != null) {
conditions.add(" lower(PP.REG_NAME)=lower(?)");
}
if (propertyValue != null) {
conditions.add(" PP.REG_VALUE LIKE ?");
}
}
if(mediaType != null){
conditions.add("R.REG_MEDIA_TYPE LIKE ?");
}
if (customSearchValues.size() > 0) {
StringBuffer propertyClause = new StringBuffer();
boolean firstTime = true;
for (Map.Entry<String, String> e : customSearchValues.entrySet()) {
if (!e.getValue().trim().equals("")) {
if (firstTime) {
propertyClause.append(" lower(PP.REG_NAME)=lower(\'").append(e.getKey()).append("\')")
.append(" AND PP.REG_VALUE LIKE ?");
firstTime = false;
} else {
propertyClause.append(" AND lower(PP.REG_NAME)=lower(\'").append(e.getKey()).append("\')")
.append(" AND PP.REG_VALUE LIKE ?");
}
}
}
if (!(propertyClause.toString().equals(""))) {
conditions.add(propertyClause.toString());
}
}
if (conditions.size() == 0) {
return null;
}
StringBuffer query = new StringBuffer();
query.append("SELECT R.REG_PATH_ID, R.REG_NAME FROM REG_RESOURCE R");
for (String table : tables) {
query.append(table);
}
boolean first = true;
for (String condition : conditions) {
if (first) {
query.append(" WHERE ");
first = false;
} else {
query.append(" AND ");
}
query.append(condition);
}
return query.toString();
}
}