/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.query.xwql.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.xwiki.bridge.DocumentAccessBridge;
import org.xwiki.query.jpql.node.PPath;
import org.xwiki.query.jpql.node.PXObjectDecl;
import org.xwiki.query.jpql.node.Start;
/**
* Contains information retrieved from query.
*/
public class QueryContext
{
/**
* Parse tree of a query.
*/
private Start tree;
/**
* Map from document alias to its description.
*/
private Map<String, DocumentInfo> documents = new HashMap<String, DocumentInfo>();
/**
* Map from object alias to its description.
*/
private Map<String, ObjectInfo> objects = new HashMap<String, ObjectInfo>();
private AliasGenerator aliasGenerator = new AliasGenerator();
private DocumentAccessBridge documentAccessBridge;
public QueryContext(Start tree, DocumentAccessBridge documentAccessBridge)
{
this.tree = tree;
this.documentAccessBridge = documentAccessBridge;
}
public Start getTree()
{
return tree;
}
public AliasGenerator getAliasGenerator()
{
return aliasGenerator;
}
public class DocumentInfo
{
public String alias;
/**
* Map from unnamed object's class name to description. unnamed object is object declaration in where clause:
* "where doc.object('Class').prop=1"
*/
public Map<String, ObjectInfo> unnamedObjects = new HashMap<String, ObjectInfo>();
}
public class ObjectInfo
{
public String docAlias;
public String className;
public String alias;
public String customMappingAlias;
/**
* Properties appeared in query
*/
public Map<String, PropertyInfo> properties = new LinkedHashMap<String, PropertyInfo>();
public ObjectInfo(String docAlias, String className, String objAlias)
{
this.className = className;
this.docAlias = docAlias;
this.alias = objAlias;
}
public PropertyInfo addProperty(String propname, PPath location)
{
PropertyInfo prop = properties.get(propname);
if (prop == null) {
prop = new PropertyInfo(propname, this);
properties.put(propname, prop);
}
prop.locations.add(location);
return prop;
}
public boolean isCustomMapped() throws Exception
{
for (PropertyInfo p : properties.values()) {
if (p.isCustomMapped()) {
return true;
}
}
return false;
}
}
public class PropertyInfo
{
public ObjectInfo object;
public String name;
public String alias;
public PropertyInfo(String name, ObjectInfo object)
{
this.name = name;
this.object = object;
}
public List<PPath> locations = new ArrayList<PPath>();
public String getType() throws Exception
{
return documentAccessBridge.getPropertyType(object.className, name);
}
public boolean isCustomMapped() throws Exception
{
return documentAccessBridge.isPropertyCustomMapped(object.className, name);
}
public String getValueField() throws Exception
{
String type = getType();
if (type.endsWith("DBStringListProperty")) {
return "list";
} else if (type.endsWith("StringListProperty")) {
return "textValue";
} else {
return "value";
}
}
}
/**
* Map from tree node to object it represent.
*/
private Map<PXObjectDecl, ObjectInfo> nodeToObject = new HashMap<PXObjectDecl, ObjectInfo>();
public ObjectInfo addObject(String docAlias, String className, String objAlias, PXObjectDecl node)
{
DocumentInfo di = getDocument(docAlias);
if (di == null) {
throw new InvalidQueryException("Can't find document alias [" + docAlias + "]");
}
ObjectInfo res = new ObjectInfo(docAlias, className, objAlias);
if (objAlias != null) {
objects.put(objAlias, res);
} else if (di.unnamedObjects.get(className) == null) {
di.unnamedObjects.put(className, res);
} else {
res = di.unnamedObjects.get(className);
}
nodeToObject.put(node, res);
return res;
}
public void addDocument(String alias)
{
if (documents.get(alias) != null && !"doc".equals(alias)) {
throw new InvalidQueryException("Redeclaration of document [" + alias + "]");
}
documents.put(alias, new DocumentInfo());
}
public DocumentInfo getDocument(String alias)
{
return documents.get(alias);
}
public ObjectInfo getObject(String objAlias)
{
return objects.get(objAlias);
}
public ObjectInfo getObject(PXObjectDecl node)
{
return nodeToObject.get(node);
}
/**
* @return all objects used in query.
*/
public Collection<ObjectInfo> getObjects()
{
List<ObjectInfo> res = new ArrayList<ObjectInfo>();
res.addAll(objects.values());
for (DocumentInfo di : documents.values()) {
res.addAll(di.unnamedObjects.values());
}
return res;
}
public Set<String> getDocuments()
{
return documents.keySet();
}
String DocumentFromName = "Document";
}