/*******************************************************************************
blogger-cli Консольные инструменты по работе с blogger.com
(с) Камнев Георгий Павлович 2011 GPLv2
Данная программа является свободным программным обеспечением. Вы вправе
распространять ее и/или модифицировать в соответствии с условиями версии 2
либо по вашему выбору с условиями более поздней версии
Стандартной Общественной Лицензии GNU, опубликованной Free Software Foundation.
Мы распространяем данную программу в надежде на то, что она будет вам полезной,
однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ,
в том числе ГАРАНТИИ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ
и ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ.
Для получения более подробной информации ознакомьтесь
со Стандартной Общественной Лицензией GNU.
Вместе с данной программой вы должны были получить экземпляр
Стандартной Общественной Лицензии GNU.
Если вы его не получили, сообщите об этом в Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*******************************************************************************/
package org.gocha.jdk;
import java.io.StringWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import org.gocha.text.IndentStackWriter;
import org.gocha.text.TextUtil;
/**
* Генератор Java кода - шаблона сообщений.<br/>
*
* Данный генератор, создает исходный код для формирования текстовых сообщений.
* Текстовое сообщение - это некий шаблон в котором указаны куда подставлять значения переменных.<br/><br/>
* Вот пример шаблона: <br/>
* <font face="monospace">Hello <b>{0}</b></font> <br/>
* {0} - Это место куда будет подставлено значение переданной переменной.<br/>
* <br/>
* Так несколько сооблщений объединяются в интерфейс следующего вида:<br/>
* <pre style="color:blue">
* public interface TestMessages
* {
* @template(def="Hello {0}")
* String hello(String userName);
* }
* </pre>
* Используя рефлексию генерируется класс-реализация: <br/>
* <pre style="color:blue"> gen = new TemplateGenerator();
* gen.setTemplateInterface(TestMessages.class);
* gen.setClassName("torg.gocha.text.TestMessagesImpl");
*
* TemplateGenerator.GeneratedSource src = gen.generateJavaCode();
* System.out.println(src.getSource());
* </pre>
* Результат генерации выглдит так:
*<pre style="color:blue">package org.gocha.text;
*
import java.util.Map;
import org.gocha.text.TextUtil;
public class TestMessagesImpl
implements
org.gocha.jdk.TestMessages
{
protected Map templates = null;
public TestMessagesImpl ( Map templates )
{
this.templates = templates;
}
public String hello ( java.lang.String arg0 )
{
if ( templates.containsKey( "hello" ) ){
Object tmplObj = templates.get( "hello" );
if( tmplObj!=null ){
String tmplString = tmplObj.toString();
return TextUtil.template( tmplString , arg0 );
}
}
return TextUtil.template( "Hello {0}", arg0 );
}
}</pre>
* <br/>
* Потом что бы использовать этот объект в коде:<br/>
* <pre style="color:blue">
* Map<String,String> templates = new HashMap<String, String>();
* templates.put("hello", "Привет {0}");
*
* TestMessagesImpl tmplateObject = new TestMessagesImpl( templates );
* System.out.println( tmplateObject.hello( "Jhon" ) );
* </pre>
* Для формирования значения из шаблона используется класс org.gocha.text.TextUtil
* @author gocha
* @see org.gocha.text.TextUtil#template(java.lang.String, java.lang.Object[])
*/
public class TemplateGenerator
{
public TemplateGenerator(){
}
@java.lang.annotation.Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface template{
String def() default "";
}
// <editor-fold defaultstate="collapsed" desc="templateInterface">
private Class templateInterface = null;
public Class getInterface() {
return templateInterface;
}
public void setInterface(Class templateInterface) {
this.templateInterface = templateInterface;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="package and class name">
protected String getPackageName() {
String _className = getClassName();
String shortClazzName = _className;
String pkg = null;
if (_className.contains(".")) {
int idx = _className.lastIndexOf(".");
pkg = _className.substring(0, idx);
pkg = TextUtil.trimEnd(pkg, ".");
pkg = TextUtil.trimStart(pkg, ".");
shortClazzName = _className.substring(idx);
shortClazzName = TextUtil.trimStart(shortClazzName, ".");
}
return pkg;
}
protected String getShortClassName() {
String _className = getClassName();
String shortClazzName = _className;
String pkg = null;
if (_className.contains(".")) {
int idx = _className.lastIndexOf(".");
pkg = _className.substring(0, idx);
pkg = TextUtil.trimEnd(pkg, ".");
pkg = TextUtil.trimStart(pkg, ".");
shortClazzName = _className.substring(idx);
shortClazzName = TextUtil.trimStart(shortClazzName, ".");
}
return shortClazzName;
}// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="className">
private String className = "className";
public String getClassName() {
if( className==null )className = "className";
return className;
}
public void setClassName(String className) {
this.className = className;
}// </editor-fold>
public static class GeneratedSource{
protected String source = null;
protected Map<String,String> defaultTemplates = null;
public GeneratedSource(String source,Map<String,String> defTemplates){
this.source = source;
this.defaultTemplates = defTemplates;
}
public Map<String, String> getDefaultTemplates() {
return defaultTemplates;
}
public String getSource() {
return source;
}
}
private Map<String,String> defTemplates = null;
public GeneratedSource generateJavaCode(){
Class tmplItf = getInterface();
if( tmplItf==null )
throw new IllegalStateException("getTemplateInterface() == null");
StringWriter sw = new StringWriter();
IndentStackWriter writer = new IndentStackWriter(sw);
writer.indent(" ");
writer.level(0);
if( !tmplItf.isInterface() )
throw new IllegalStateException("getTemplateInterface() is not interface");
defTemplates = new HashMap<String, String>();
gen(writer);
writer.flush();
GeneratedSource src = new GeneratedSource(sw.toString(), defTemplates);
return src;
}
public interface TemplateMapProperties{
public Map<String,String> getTemplateMap();
}
private void gen(IndentStackWriter writer){
Class tmplItf = getInterface();
String shortClazzName = getShortClassName();
String pkg = getPackageName();
if( pkg!=null ){
writer.println("package "+pkg+";");
writer.println("");
}
genImport(writer);
writer.println("public class " + shortClazzName);
//implements
writer.incLevel();
writer.println("implements ");
writer.incLevel();
writer.println(tmplItf.getName());
// writer.println(", "+TemplateGenerator.class.getName()+".TemplateMapProperties");
writer.decLevel();
writer.decLevel();
//implements end
writer.println("{");
writer.incLevel();
genFields(writer);
genConstruct(writer);
// genImplTemplateMapProperties(writer);
Method[] methods = tmplItf.getMethods();
for( Method m : methods ){
genMeth(writer, m);
}
writer.decLevel();
writer.println("}");
}
private void genImport(IndentStackWriter writer){
writer.println("import java.util.Map;");
writer.println("import org.gocha.text.TextUtil;");
writer.println("");
}
private void genFields(IndentStackWriter writer){
writer.println("protected Map templates = null;");
}
// private void genImplTemplateMapProperties(IndentStackWriter writer){
// writer.println("public Map<String,String> getTemplateMap()");
// writer.println("{");
// writer.incLevel();
// writer.println("return this.templates;");
// writer.decLevel();
// writer.println("}");
// }
private void genConstruct(IndentStackWriter writer){
String clazzName = getShortClassName();
writer.println("public "+clazzName+" ( Map templates )");
writer.println("{");
writer.incLevel();
writer.println("this.templates = templates;");
writer.decLevel();
writer.println("}");
}
private void genMeth(IndentStackWriter writer,Method m){
int mod = m.getModifiers();
if( Modifier.isStatic(mod) )return;
Class retType = m.getReturnType();
if( !retType.equals(String.class) )return;
Class[] mThrows = m.getExceptionTypes();
if( mThrows.length>0 )return;
String defTempl = null;
TemplateGenerator.template tmpl =
m.getAnnotation(TemplateGenerator.template.class);
if( tmpl!=null && tmpl.def()!=null && tmpl.def().length()>0 )
defTempl = tmpl.def();
// Type[] genParams = m.getGenericParameterTypes();
// Type[] genThrows = m.getGenericExceptionTypes();
// Type genRet = m.getGenericReturnType();
// genParams[0].getClass().
// if( genParams.length>0 )return;
// if( genThrows.length>0 )return;
// if( genRet!=null )return;
Class[] mParams = m.getParameterTypes();
String methodName = m.getName();
writer.print("public ");
writer.print("String ");
writer.print(methodName);
writer.print(" ( ");
int idx = -1;
for(Class paramClass:mParams){
idx++;
if( idx>0 )writer.print(", ");
writer.print(paramClass.getName());
writer.print(" ");
writer.print("arg");
writer.print(idx);
}
writer.println(" )");
writer.println("{");
writer.incLevel();
// body
writer.println("Object[] args = new Object[]{");
for( int i=0; i<mParams.length; i++ ){
if( i>0 )writer.print(", ");
writer.println("arg"+i);
}
writer.println("};");
writer.println("if ( templates.containsKey( \""+methodName+"\" ) ){");
writer.incLevel();
writer.println("Object tmplObj = templates.get( \""+methodName+"\" );");
writer.println("if( tmplObj!=null ){");
writer.incLevel();
writer.println("String tmplString = tmplObj.toString();");
// writer.println("String tmpl = templates.get( \""+methodName+"\" );");
writer.print("return TextUtil.template( tmplString ");
// for( int i=0; i<mParams.length; i++ ){
// writer.print(", arg"+i);
// }
writer.print( ", args" );
writer.println(" );");
writer.decLevel();
writer.println("}");
writer.decLevel();
writer.println("}");
writer.print("return TextUtil.template( ");
if( defTempl!=null ){
writer.print(TextUtil.encodeStringConstant(defTempl));
defTemplates.put(methodName, defTempl);
}else{
// generate template by args
StringBuilder t = new StringBuilder();
t.append(methodName);
t.append("(");
for( int i=0; i<mParams.length; i++ ){
if( i>0 )t.append(", ");
t.append("{");
t.append(i);
t.append("}");
}
t.append(")");
writer.print(TextUtil.encodeStringConstant(t.toString()));
defTemplates.put(methodName, t.toString());
}
// for( int i=0; i<mParams.length; i++ ){
// writer.print(", arg"+i);
// }
writer.print(", args");
writer.println(" );");
// body end
writer.decLevel();
writer.println("}");
}
}