/*
Copyright [2013-2014] eBay Software Foundation
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.
*/
/*
Copyright 2012 eBay Software Foundation
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 com.ebay.cloud.cms.query.executor.result;
import java.util.Collection;
import java.util.List;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.ObjectNode;
import com.ebay.cloud.cms.dal.search.ISearchField;
import com.ebay.cloud.cms.dal.search.SearchGroup;
import com.ebay.cloud.cms.dal.search.SearchProjection;
import com.ebay.cloud.cms.dal.search.impl.field.ProjectionField;
import com.ebay.cloud.cms.metadata.model.InternalFieldEnum;
import com.ebay.cloud.cms.metadata.model.MetaAttribute;
import com.ebay.cloud.cms.metadata.model.MetaClass;
import com.ebay.cloud.cms.metadata.model.MetaField;
import com.ebay.cloud.cms.metadata.model.MetaRelationship;
import com.ebay.cloud.cms.metadata.mongo.converter.ObjectConverter;
import com.ebay.cloud.cms.query.parser.ParseQueryNode;
import com.ebay.cloud.cms.query.service.QueryContext;
public class QueryProjectionVisitor {
private static final ObjectMapper mapper = ObjectConverter.mapper;
private final ArrayNode displayNode;
private final QueryContext queryContext;
private ObjectNode currentNode;
QueryProjectionVisitor(QueryContext qryContext) {
this.queryContext = qryContext;
displayNode = JsonNodeFactory.instance.arrayNode();
}
public ArrayNode getDisplayNode() {
return displayNode;
}
public void findProjection(ParseQueryNode queryNode) {
MetaClass curMeta = queryNode.getMetaClass();
findMetaProjection(curMeta, queryNode);
for (MetaClass typeCastMeta : queryNode.getTypeCast()) {
findMetaProjection(typeCastMeta, queryNode);
}
}
private void findMetaProjection(MetaClass metadata, ParseQueryNode queryNode) {
if (queryNode.isUserDisplay()) {
createJsonNode(metadata);
if (queryNode.isRootDisplay()) {
displayNode.add(currentNode);
}
} else {
createJsonNode(metadata);
}
rewriteProjection(queryNode);
for (String project : queryNode.getProjectionFields()) {
MetaField metaField = metadata.getFieldByName(project);
traverse(metaField, queryNode);
}
}
private void rewriteProjection(ParseQueryNode queryNode) {
MetaClass metadata = queryNode.getMetaClass();
SearchProjection projection = queryNode.getProjection();
if (queryNode.getGroup() == null) {
// add default fields
ProjectionField idField = new ProjectionField(metadata.getFieldByName(InternalFieldEnum.ID.getName()),
true, queryContext.getRegistration().searchStrategy);
projection.addField(idField);
// add all fields for star selection
if (projection.hasStar()) {
Collection<MetaField> metaFields = metadata.getFields();
for (MetaField metaField : metaFields) {
projection.addField(new ProjectionField(metaField, true, queryContext.getRegistration().searchStrategy));
}
}
} else {
SearchGroup group = queryNode.getGroup();
// add default fields
if (projection.isEmpty()) {
projection.addField(ProjectionField.STAR);
}
// add all fields for star selection
if (projection.hasStar()) {
Collection<ISearchField> searchFields = group.getProjectFields();
for (ISearchField field : searchFields) {
projection.addField(field);
}
}
}
}
private void createJsonNode(MetaClass metadata) {
currentNode = mapper.valueToTree(metadata);
currentNode.remove("fields");
currentNode.remove("options");
currentNode.put("fields", JsonNodeFactory.instance.objectNode());
}
private void traverse(MetaField field, ParseQueryNode queryNode) {
if (field == null) {
return;
}
if (field instanceof MetaAttribute) {
addAttribute(field);
} else {
addRelationship((MetaRelationship) field, queryNode);
}
}
private void addRelationship(MetaRelationship field, ParseQueryNode queryNode) {
ObjectNode relNode = null;
if (currentNode != null) {
relNode = mapper.valueToTree(field);
((ObjectNode) currentNode.get("fields")).put(field.getName(), relNode);
}
List<ParseQueryNode> nextNodes = queryNode.getNextQueryNode(field);
if (nextNodes != null) {
for (ParseQueryNode nextNode : nextNodes) {
ObjectNode oldCurNode = currentNode;
// first for the query node metaclass
MetaClass meta = nextNode.getMetaClass();
findMetaProjection(meta, nextNode);
addToRelNode(relNode, meta);
// type casts
for (MetaClass typeCastMeta : nextNode.getTypeCast()) {
findMetaProjection(typeCastMeta, nextNode);
addToRelNode(relNode, typeCastMeta);
}
currentNode = oldCurNode;
}
}
}
private void addToRelNode(ObjectNode relNode, MetaClass meta) {
if (relNode != null) {
JsonNode node = relNode.get("refDataType");
if (!(node instanceof ObjectNode)) {
node = JsonNodeFactory.instance.objectNode();
relNode.put("refDataType", node);
}
((ObjectNode) node).put(meta.getName(), currentNode);
}
}
private void addAttribute(MetaField field) {
if (currentNode != null) {
((ObjectNode) currentNode.get("fields")).put(field.getName(), mapper.valueToTree(field));
}
}
}