All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onetwo.common.db.filequery.MultipCommentsSqlFileParser Maven / Gradle / Ivy

The newest version!
package org.onetwo.common.db.filequery;

import java.beans.PropertyDescriptor;
import java.util.Enumeration;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.onetwo.common.db.DataBase;
import org.onetwo.common.db.dquery.DbmSqlFileResource;
import org.onetwo.common.db.filequery.SimpleSqlFileLineLexer.LineToken;
import org.onetwo.common.db.spi.NamedQueryFile;
import org.onetwo.common.db.spi.NamedQueryInfoParser;
import org.onetwo.common.db.spi.QueryConfigData;
import org.onetwo.common.db.spi.QueryContextVariable.QueryGlobalVariable;
import org.onetwo.common.db.spi.SqlDirectiveExtractor;
import org.onetwo.common.log.JFishLoggerFactory;
import org.onetwo.common.propconf.JFishProperties;
import org.onetwo.common.propconf.ResourceAdapter;
import org.onetwo.dbm.exception.DbmException;
import org.onetwo.dbm.exception.FileNamedQueryException;
import org.slf4j.Logger;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.collect.ImmutableList;

/****
 * file example:
 	@name: findById
 	@propertyName1: value1
 	@propertyName2: value2
 	
 		sql.....
 		
 * 
 * @author wayshall
 *
 */
public class MultipCommentsSqlFileParser implements NamedQueryInfoParser {
	
	/***
	 * 这个实现有问题,少了空格
	 * @author wayshall
	 *
	 */
	@Deprecated
	public static class SimpleDirectiveExtractor implements SqlDirectiveExtractor {
		public static final String DIRECTIVE_PREFIX = SimpleSqlFileLineLexer.COMMENT + ">";//-->
		public static final String DIRECTIVE_START = DIRECTIVE_PREFIX + "[";
		public static final String DIRECTIVE_END = "]";

		@Override
		public boolean isDirective(String value) {
			return value.startsWith(DIRECTIVE_START) && value.endsWith(DIRECTIVE_END);
		}

		@Override
		public String extractDirective(String value) {
//			String directive = StringUtils.substringBetween(value, DIRECTIVE_START, DIRECTIVE_END);// value.substring(SimpleSqlFileLineLexer.COMMENT.length());
			String directive = StringUtils.substringAfter(value, DIRECTIVE_PREFIX);// value.substring(SimpleSqlFileLineLexer.COMMENT.length());
			return directive;
		}
		
	}
	
	/****
	 * 重新实现注释型指令,使用"-- >"
	 * @author wayshall
	 *
	 */
	public static class CustomDirectiveExtractor implements SqlDirectiveExtractor {
		private String prefix;
		private String start;
		private String end;

		public CustomDirectiveExtractor(String prefix, String start, String end) {
			super();
			this.prefix = prefix;
			this.start = prefix+start;
			this.end = end;
		}

		@Override
		public boolean isDirective(String value) {
			return value.startsWith(start) && value.endsWith(end);
		}

		@Override
		public String extractDirective(String value) {
			String directive = StringUtils.substringAfter(value, prefix);
			return directive;
		}
	}
	
	public static final String GLOBAL_NS_KEY = "global";
	public static final String AT = "@";
//	public static final String EQUALS_MARK = "=";
	public static final String COLON = ":";
	
	
	protected final Logger logger = JFishLoggerFactory.getLogger(this.getClass());
	protected boolean debug = false;
//	protected SqlDirectiveExtractor sqlDirectiveExtractor = new SimpleDirectiveExtractor();
	protected List sqlDirectiveExtractors = ImmutableList.of(new SimpleDirectiveExtractor(), 
																					new CustomDirectiveExtractor("-- >", "[", "]"));
	@Autowired(required=false)
	private List queryGlobalVariable;
	
	@Override
	public void parseToNamedQueryFile(NamedQueryFile namespaceInfo, DbmSqlFileResource sqlFile) {
		if(!sqlFile.exists()){
			logger.info("sql file is not exists, ignore parse. namespace: " + namespaceInfo.getNamespace());
			return ;
		}
		if(!sqlFile.getName().endsWith(POSTFIX)){
			logger.info("file["+sqlFile.getName()+" is not a ["+POSTFIX+"] file, ignore it.");
			return ;
		}
		SimpleSqlFileLineLexer lineLexer = new SimpleSqlFileLineLexer(createLineReader(sqlFile));
		lineLexer.nextLineToken();
		while(lineLexer.getLineToken()!=LineToken.EOF){
			LineToken token = lineLexer.getLineToken();
			if(debug)
				logger.info("current token {}  ", token);
			
			switch (token) {
				case MULTIP_COMMENT:
					this.parseQueryStatement(lineLexer, namespaceInfo, sqlFile);
					break;
					
				default:
					if(debug)
						logger.info("ignore token {} : {} ", token, lineLexer.getLineBuf());
					
					lineLexer.nextLineToken();
					break;
			}
		}
		
	}
	
	protected QueryConfigData createQueryConfigData() {
		QueryConfigData config = new QueryConfigData();
		
		if (queryGlobalVariable!=null) {
			config.setVariables(queryGlobalVariable.toArray(new QueryGlobalVariable[0]));
		}
		
		return config;
	}
	
	protected void parseQueryStatement(SimpleSqlFileLineLexer lineLexer,
										NamedQueryFile namespaceInfo, DbmSqlFileResource f){
		List comments = lineLexer.getLineBuf();
		JFishProperties config = parseComments(comments);
		//name
		//没有发现 @name 属性的注释,抛错……
//		String name = config.getAndThrowIfEmpty(DbmNamedFileQueryInfo.NAME_KEY);
		String name = config.getProperty(FileBaseNamedQueryInfo.NAME_KEY);
		//没有发现 @name 属性的注释,忽略
		if(StringUtils.isBlank(name)){
			scanSqlContent(lineLexer);
			return ;
		}
		config.remove(FileBaseNamedQueryInfo.NAME_KEY);
		
		FileBaseNamedQueryInfo bean = namespaceInfo.getNamedProperty(name);
		String sqlPropertyName = "value";
		if(bean==null){
			bean = new FileBaseNamedQueryInfo();
			bean.setDbmNamedQueryFile(namespaceInfo);
			bean.setSrcfile(f);
			bean.setQueryConfig(createQueryConfigData());

			bean.setName(name);
			bean.setConfig(config);
			bean.setDataBase(f.getDatabase());

			namespaceInfo.put(bean.getName(), bean, true);

			//别名
			if(config.containsKey(FileBaseNamedQueryInfo.ALIAS_KEY)){
				bean.setAliasList(config.getStringList(FileBaseNamedQueryInfo.ALIAS_KEY, ","));
				config.remove(FileBaseNamedQueryInfo.ALIAS_KEY);
			}
			
			/*if(config.containsKey(JFishNamedFileQueryInfo.MATCHER_KEY)){
				//matcher
				String matchers = config.getProperty(JFishNamedFileQueryInfo.MATCHER_KEY);
				bean.setMatchers(Arrays.asList(StringUtils.split(matchers, JFishNamedFileQueryInfo.MATCHER_SPIT_KEY)));
				config.remove(JFishNamedFileQueryInfo.MATCHER_KEY);
				
			}*/
			if(config.containsKey(FileBaseNamedQueryInfo.PROPERTY_KEY)
					|| config.containsKey(FileBaseNamedQueryInfo.FRAGMENT_KEY)){
				throw new FileNamedQueryException("no parent query["+bean.getName()+"] found, the @property or @fragment tag must defined in a subquery, near at "
						+ "line : " + lineLexer.getLineReader().getLineNumber());
			}
		}else{
			if(config.containsKey(FileBaseNamedQueryInfo.PROPERTY_KEY)){
				//property:propertyName
				sqlPropertyName = config.getProperty(FileBaseNamedQueryInfo.PROPERTY_KEY);
				config.remove(FileBaseNamedQueryInfo.PROPERTY_KEY);
				
			}else if(config.containsKey(FileBaseNamedQueryInfo.FRAGMENT_KEY)){
				//fragment[fragmentValue]=sql
				sqlPropertyName = FileBaseNamedQueryInfo.FRAGMENT_KEY + "[" + 
															config.getProperty(FileBaseNamedQueryInfo.FRAGMENT_KEY)
																	+ "]";
				config.remove(FileBaseNamedQueryInfo.FRAGMENT_KEY);
				
			}else{
				throw new FileNamedQueryException("named query["+name+"]is repeated! rename it or set a @property or @fragment directive "
						+ "near at line : " + lineLexer.getLineReader().getLineNumber());
			}
//			sqlPropertyName = config.getProperty(PROPERTY_KEY);
		}
		
		
		if(debug)
			logger.info("config: {}", config);
		
		Enumeration keys = config.propertyNames();
		BeanWrapper beanBw = PropertyAccessorFactory.forBeanPropertyAccess(bean);
		while(keys.hasMoreElements()){
			String prop = keys.nextElement().toString();
			this.setNamedInfoProperty(beanBw, prop, config.getProperty(prop));
		}
		
		String sqlContent = scanSqlContent(lineLexer);
//		bean.setValue(buf.toString());
		beanBw.setPropertyValue(sqlPropertyName, sqlContent);
		
		if(debug)
			logger.info("value: {}", bean.getValue());
	}
	
	private String scanSqlContent(SimpleSqlFileLineLexer lineLexer){
		StringBuilder buf = new StringBuilder();
		while(lineLexer.nextLineToken()){
			if(lineLexer.getLineToken()==LineToken.EOF){
				break;
			}else if(lineLexer.getLineToken()==LineToken.MULTIP_COMMENT){
				break;
			}else if(lineLexer.getLineToken()==LineToken.ONE_LINE_COMMENT){
				String value = StringUtils.join(lineLexer.getLineBuf(), " ");
				/*if(sqlDirectiveExtractor.isDirective(value)){//-->[#if ... ]
					buf.append(sqlDirectiveExtractor.extractDirective(value)).append(" ");
				}*/
				this.parseSqlDirectiveExtractors(buf, value);
				continue;
			}else if(lineLexer.getLineToken()==LineToken.CONTENT){
				String value = StringUtils.join(lineLexer.getLineBuf(), " ");
//				buf.append(value).append(" ");
				buf.append(value).append('\n');
			}else{
				throw new FileNamedQueryException("error syntax: " + lineLexer.getLineToken());
			}
		}
		return buf.toString();
	}
	
	protected void parseSqlDirectiveExtractors(StringBuilder buf, String value){
		this.sqlDirectiveExtractors.forEach(sqlDirectiveExtractor->{
			if(sqlDirectiveExtractor.isDirective(value)){//-->[#if ... ]
				buf.append(sqlDirectiveExtractor.extractDirective(value)).append(" ");
			}
		});
	}
	
	
	protected JFishProperties parseComments(List comments){
		JFishProperties config = new JFishProperties();
		for(final String comment : comments){
//			logger.info("comment: {}", comment);
			if(comment.startsWith(AT)){
				String line = comment.substring(AT.length());
				String[] strs = StringUtils.split(line, COLON);
				if(strs.length==2){
					config.setProperty(strs[0].trim(), strs[1].trim());
				}else{
					throw new FileNamedQueryException("error syntax for config: " + comment);
				}
			}
		}
		return config;
	}
	
	protected void setNamedInfoProperty(BeanWrapper beanBw, String prop, Object val){
		if(prop.indexOf(FileBaseNamedQueryInfo.DOT_KEY)!=-1){
			prop = org.onetwo.common.utils.StringUtils.toCamel(prop, FileBaseNamedQueryInfo.DOT_KEY, false);
		}
		PropertyDescriptor pd = beanBw.getPropertyDescriptor(prop);
		if (pd.getPropertyType()==DataBase.class) {
			val = DataBase.of(val.toString());
		}
		try {
			beanBw.setPropertyValue(prop, val);
		} catch (Exception e) {
			FileBaseNamedQueryInfo bean = (FileBaseNamedQueryInfo)beanBw.getWrappedInstance();
			throw new DbmException("NamedQuery[" + bean.getFullName() + "] set property error. perperty: " + prop + ", value: " + val);
		}
		/*try {
			ReflectUtils.setExpr(bean, prop, val);
		} catch (Exception e) {
			logger.error("set value error : "+prop);
			LangUtils.throwBaseException(e);
		}*/
	}
	
/*
	protected List readResourceAsList(ResourceAdapter f){
		if(f.isSupportedToFile())
			return FileUtils.readAsList(f.getFile());
		else
			throw new UnsupportedOperationException();
	}*/

	protected SimpleSqlFileLineReader createLineReader(ResourceAdapter f){
//		return new SimpleSqlFileLineReader(readResourceAsList(f));
		return new SimpleSqlFileLineReader(f.readAsList());
	}
	public void setDebug(boolean debug) {
		this.debug = debug;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy