/**
*
* Copyright 2014 The Darks ORM Project (Liu lihua)
*
* 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 darks.orm.core.config.sqlmap;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Attribute;
import org.dom4j.Element;
import org.dom4j.Node;
import darks.orm.app.QueryEnumType;
import darks.orm.core.aspect.jython.PythonBuilder;
import darks.orm.core.data.tags.AbstractTag;
import darks.orm.core.data.tags.RootTag;
import darks.orm.core.data.tags.TagsFactory;
import darks.orm.core.data.tags.impl.TextTag;
import darks.orm.core.data.xml.AspectData;
import darks.orm.core.data.xml.AspectData.AspectType;
import darks.orm.core.data.xml.DMLData;
import darks.orm.core.data.xml.DMLData.DMLType;
import darks.orm.core.data.xml.DMLQueryData;
import darks.orm.core.data.xml.DMLQueryData.DMLQueryDataType;
import darks.orm.core.data.xml.DMLUpdateData;
import darks.orm.core.factory.TransformFactory;
import darks.orm.exceptions.ConfigException;
import darks.orm.log.Logger;
import darks.orm.log.LoggerFactory;
import darks.orm.util.StringHelper;
@SuppressWarnings("unchecked")
public class DMLConfigReader
{
private static final Logger logger = LoggerFactory.getLogger(DMLConfigReader.class);
private SqlMapConfiguration sqlMapConfig;
public DMLConfigReader(SqlMapConfiguration sqlMapConfig)
{
this.sqlMapConfig = sqlMapConfig;
}
/**
* Read sqlmap DML xml element
*
* @param element Xml element
*/
public void reader(Element element)
{
String namesp = element.attributeValue("namespace");
if (namesp == null)
namesp = "";
try
{
for (Iterator<Element> it = element.elementIterator(); it.hasNext();)
{
Element el = it.next();
String name = el.getName().trim();
if ("Query".equalsIgnoreCase(name))
{
readQuery(el, namesp);
}
else if ("Update".equalsIgnoreCase(name))
{
readUpdate(el, namesp);
}
else if ("tag".equalsIgnoreCase(name))
{
readTag(el, namesp);
}
}
}
catch (Exception e)
{
throw new ConfigException(e.getMessage(), e);
}
}
/**
* Read and parse extern tags
*
* @param element tag element
* @param namesp namespace
* @throws Exception
*/
private void readTag(Element element, String namesp) throws Exception
{
String id = element.attributeValue("id");
if (id == null || "".equals(id.trim()))
{
return;
}
RootTag rootTag = new RootTag();
if (!"".equals(namesp))
{
if (!namesp.endsWith("."))
namesp += ".";
}
parseSqlTag(rootTag, element, namesp);
sqlMapConfig.addTag(namesp + id, rootTag);
}
/**
* Read and parse query tags
*
* @param element Query tag element
* @param namesp namespace
* @throws Exception
*/
private DMLData readQuery(Element element, String namesp) throws Exception
{
if (!"".equals(namesp))
{
if (!namesp.endsWith("."))
namesp += ".";
}
DMLData dmlData = new DMLData();
dmlData.setType(DMLType.Query);
DMLQueryData queryData = new DMLQueryData();
queryData.setQueryType(QueryEnumType.Auto);
queryData.setAutoCascade(true);
dmlData.setQueryData(queryData);
try
{
for (Iterator<Attribute> it = element.attributeIterator(); it.hasNext();)
{
Attribute attr = it.next();
readQueryAttribute(attr, dmlData, queryData);
}
}
catch (Exception e)
{
throw new ConfigException(e.getMessage(), e);
}
if (queryData.getResultClass() == null)
{
throw new ConfigException("Sqlmap query " + dmlData.getId() + " loss result class config");
}
if (dmlData.getId() == null)
return null;
RootTag rootTag = new RootTag();
parseSqlTag(rootTag, element, namesp);
dmlData.setSqlTag(rootTag);
String sql = element.getTextTrim();
if (sql != null && !"".equals(sql))
{
queryData.setQueryDataType(DMLQueryDataType.Simple);
queryData.setSQL(sql);
}
else
{
if (!readConstitute(element, queryData))
{
if (!readSelect(element, queryData, ""))
{
return null;
}
}
}
AspectData aspectData = parseAspectXml(element);
queryData.setAspectData(aspectData);
sqlMapConfig.addDMLData(namesp + dmlData.getId(), dmlData);
return dmlData;
}
private void readQueryAttribute(Attribute attr, DMLData dmlData, DMLQueryData queryData) throws Exception
{
String name = attr.getName().trim();
String value = attr.getValue().trim();
if ("id".equalsIgnoreCase(name))
{
dmlData.setId(value);
}
else if ("resultType".equalsIgnoreCase(name))
{
queryData.setResultType(value);
Class<?> cls = TransformFactory.getInstance().stringToEntityClass(value);
if (cls == null)
{
throw new ConfigException(value + " does not exists");
}
queryData.setResultClass(cls);
}
else if ("autoCascade".equalsIgnoreCase(name))
{
if ("true".equalsIgnoreCase(value))
queryData.setAutoCascade(true);
else if ("false".equalsIgnoreCase(value))
queryData.setAutoCascade(false);
}
else if ("alias".equalsIgnoreCase(name))
{
queryData.setAlias(value);
}
else if ("attribute".equalsIgnoreCase(name))
{
queryData.setAttribute(value);
}
else if ("queryType".equalsIgnoreCase(name))
{
if ("object".equalsIgnoreCase(value))
queryData.setQueryType(QueryEnumType.Object);
else if ("list".equalsIgnoreCase(value))
queryData.setQueryType(QueryEnumType.List);
else if ("page".equalsIgnoreCase(value))
queryData.setQueryType(QueryEnumType.Page);
else
queryData.setQueryType(QueryEnumType.Auto);
}
else if ("cache".equalsIgnoreCase(name))
{
if ("auto".equalsIgnoreCase(value))
dmlData.setAutoCache(true);
else if ("manual".equalsIgnoreCase(value))
dmlData.setAutoCache(false);
}
else if ("cacheId".equalsIgnoreCase(name))
{
dmlData.setCacheId(value);
}
else if ("values".equalsIgnoreCase(name))
{
queryData.setValuesParam(StringHelper.parseParamFlag(value));
}
else if ("page".equalsIgnoreCase(name))
{
queryData.setPageParam(StringHelper.parseParamFlag(value));
}
else if ("pageSize".equalsIgnoreCase(name))
{
queryData.setPageSizeParam(StringHelper.parseParamFlag(value));
}
}
/**
* Read constitute query
*
* @param element query element
* @param queryData Query data
* @return If success, return true
*/
private boolean readConstitute(Element element, DMLQueryData queryData)
{
queryData.setQueryDataType(DMLQueryDataType.Constitute);
Element queryElement = element.element("query");
Element cstElement = element.element("constitute");
if (queryElement == null || cstElement == null)
return false;
String sql = queryElement.getTextTrim();
if (sql == null || "".equals(sql))
return false;
queryData.setSQL(sql);
List<Element> items = cstElement.elements("item");
for (Element item : items)
{
String value = item.attributeValue("value");
if (value == null || "".equals(value))
continue;
String exsql = item.getTextTrim();
if (exsql == null)
exsql = "";
queryData.addSQL(value, exsql);
}
return true;
}
/**
* Read select query
*
* @param element query element
* @param queryData Query data
* @param pVal Parent values
* @return If success, return true
*/
private boolean readSelect(Element element, DMLQueryData queryData, String pVal)
{
queryData.setQueryDataType(DMLQueryDataType.Select);
List<Element> selects = element.elements("select");
if (selects == null || selects.size() == 0)
return false;
for (Element sel : selects)
{
String value = sel.attributeValue("value");
if (value == null || "".equals(value))
continue;
List<Element> chsel = sel.elements("select");
if (chsel.size() > 0)
{
readSelect(sel, queryData, pVal + value + "@");
}
else
{
String sql = sel.getTextTrim();
String key = pVal + value;
if (key.endsWith("@"))
{
key = key.substring(0, key.length() - 1);
}
queryData.addSQL(key, sql);
}
}
return true;
}
/**
* Read and parse update tags
*
* @param element Update tag
* @param namesp namespace
* @throws Exception
*/
private DMLData readUpdate(Element element, String namesp) throws Exception
{
if (!"".equals(namesp))
{
if (!namesp.endsWith("."))
namesp += ".";
}
DMLData dmlData = new DMLData();
String sql = element.getTextTrim();
dmlData.setType(DMLType.Update);
DMLUpdateData updateData = new DMLUpdateData();
RootTag rootTag = new RootTag();
parseSqlTag(rootTag, element, namesp);
dmlData.setSqlTag(rootTag);
updateData.setSql(sql);
for (Iterator<Attribute> it = element.attributeIterator(); it.hasNext();)
{
try
{
Attribute at = it.next();
String name = at.getName().trim();
String value = at.getValue().trim();
if ("id".equalsIgnoreCase(name))
{
dmlData.setId(value);
}
}
catch (Exception e)
{
logger.error(e.getMessage(), e);
}
}
if (dmlData.getId() == null)
return null;
AspectData aspectData = parseAspectXml(element);
updateData.setAspectData(aspectData);
dmlData.setUpdateData(updateData);
sqlMapConfig.addDMLData(namesp + dmlData.getId(), dmlData);
return dmlData;
}
/**
* Read and parse aspect XMLs file
*
* @param element Aspect tags
* @return Aspect data
*/
private AspectData parseAspectXml(Element element)
{
Element aspectEl = element.element("aspect");
if (aspectEl == null)
return null;
AspectData aspectData = new AspectData();
boolean isNext = false;
Element jythonEl = aspectEl.element("jython");
if (jythonEl != null)
{
aspectData.setAspectType(AspectType.JYTHON);
Attribute attr = jythonEl.attribute("className");
if (attr == null)
return null;
aspectData.setClassName(attr.getValue().trim());
String text = jythonEl.getText();
if (text == null || "".equals(text.trim()))
{
String before = jythonEl.elementText("before");
String after = jythonEl.elementText("after");
if (before == null || "".equals(before.trim()))
{
if (after == null || "".equals(after.trim()))
return null;
}
text = PythonBuilder.buildBody(aspectData.getClassName(), before, after);
}
aspectData.setContent(text);
isNext = true;
}
Element pyfileEl = aspectEl.element("pyfile");
if (pyfileEl != null && isNext == false)
{
aspectData.setAspectType(AspectType.PYFILE);
Attribute attr = pyfileEl.attribute("className");
if (attr == null)
return null;
aspectData.setClassName(attr.getValue().trim());
aspectData.setContent(pyfileEl.getTextTrim());
isNext = true;
}
Element javaClassEl = aspectEl.element("javaClass");
if (javaClassEl != null && isNext == false)
{
aspectData.setAspectType(AspectType.JAVACLASS);
aspectData.setClassName(javaClassEl.getTextTrim());
isNext = true;
}
Element jsEl = aspectEl.element("javascript");
if (jsEl != null && isNext == false)
{
aspectData.setAspectType(AspectType.JAVASCRIPT);
aspectData.setContent(jsEl.getTextTrim());
isNext = true;
}
Element jsfileEl = aspectEl.element("jsfile");
if (jsfileEl != null && isNext == false)
{
aspectData.setAspectType(AspectType.JSFILE);
aspectData.setContent(jsfileEl.getTextTrim());
isNext = true;
}
if (isNext)
{
return aspectData;
}
return null;
}
private void parseSqlTag(AbstractTag parent, Element el, String namesp) throws Exception
{
AbstractTag prevTag = null;
List<Node> list = el.content();
Iterator<Node> it = list.iterator();
while (it.hasNext())
{
Node node = it.next();
switch (node.getNodeType())
{
case Node.ELEMENT_NODE:
Element childEl = (Element) node;
prevTag = parseElementTag(parent, node, childEl, namesp, prevTag);
break;
case Node.CDATA_SECTION_NODE:
case Node.TEXT_NODE:
String text = node.getText().replaceAll("\n|\t", " ").trim();
if (!"".equals(text))
{
TextTag tag = new TextTag(text, prevTag);
parent.addChild(tag);
prevTag = tag;
}
break;
}
}
}
private AbstractTag parseElementTag(AbstractTag parent, Node node, Element childEl, String namesp, AbstractTag prevTag) throws Exception
{
if ("include".equals(node.getName()))
{
String id = childEl.attributeValue("refid");
if (id.indexOf(".") < 0)
{
id = namesp + id;
}
AbstractTag externTag = sqlMapConfig.getTag(id);
if (externTag != null)
{
prevTag = externTag;
parent.addChild(externTag);
}
}
else
{
AbstractTag childTag = TagsFactory.createTag(childEl, prevTag);
if (childTag != null)
{
if (childTag.parseElement(childEl))
{
prevTag = childTag;
parent.addChild(childTag);
parseSqlTag(childTag, childEl, namesp);
}
}
}
return prevTag;
}
public SqlMapConfiguration getSqlMapConfig()
{
return sqlMapConfig;
}
public void setSqlMapConfig(SqlMapConfiguration sqlMapConfig)
{
this.sqlMapConfig = sqlMapConfig;
}
}