001package net.gdface.codegen.thrift; 002 003import org.apache.commons.cli.CommandLine; 004import org.apache.commons.cli.Options; 005import org.apache.commons.cli.ParseException; 006import org.apache.commons.configuration2.Configuration; 007import org.apache.commons.configuration2.PropertiesConfiguration; 008import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; 009import org.apache.commons.configuration2.io.FileHandler; 010 011import static com.google.common.base.Preconditions.*; 012 013import com.google.common.base.Throwables; 014import com.google.common.collect.Lists; 015import com.google.common.collect.Maps; 016 017import net.gdface.codegen.generator.CodeWriter; 018import net.gdface.codegen.generator.CxxCodeWriter; 019import net.gdface.codegen.generator.GeneratorConfiguration; 020import net.gdface.codegen.generator.JavaCodeWriter; 021 022import java.io.File; 023import java.util.List; 024import java.util.Map; 025 026/** 027 * decorator生成器参数对象 028 * @author guyadong 029 * 030 */ 031public class ThriftServiceDecoratorConfiguration extends GeneratorConfiguration 032 implements ThriftConstants{ 033 private static final String ENCODING = "UTF-8"; 034 /** 035 * 任务类型定义 036 * @author guyadong 037 * 038 */ 039 public static enum TaskType{ 040 /** 生成thrift service代码 */SERVICE("service"), 041 /** 生成thrift/swift client代码 */CLIENT("client"), 042 /** 生成基于Microsoft/thrifty client代码 */CLIENT_THRIFTY("client_thrifty"); 043 public final String folder; 044 private TaskType(String folder){ 045 this.folder = folder; 046 } 047 }; 048 /** 049 * 生成代码语言类型定义 050 * @author guyadong 051 * 052 */ 053 public static enum LanguageType{ 054 /** 生成thrift java代码 */JAVA(""), 055 /** 生成thrift c++代码 */CPP("_cpp"), 056 /** 生成thrift c++代码 */C_GLIB("_c_glib") 057 ; 058 private static LanguageType current = null; 059 /** 模板根文件夹名结尾 */ 060 public final String postfix; 061 private LanguageType(String postfix){ 062 this.postfix = postfix; 063 } 064 /** 返回对应的 {@link CodeWriter}实例 */ 065 public CodeWriter getCodeWriter(File outputFolder){ 066 switch(this){ 067 case JAVA: 068 return new JavaCodeWriter(outputFolder); 069 case CPP: 070 return new CxxCodeWriter(outputFolder); 071 case C_GLIB: 072 return new CxxCodeWriter(outputFolder); 073 default: 074 throw new UnsupportedOperationException("unsupported language type:" + this.name()); 075 } 076 } 077 public static LanguageType getCurrent() { 078 return current; 079 } 080 public synchronized static void setCurrent(LanguageType current) { 081 checkState(null == LanguageType.current 082 || LanguageType.current.equals(current), 083 "LanguageType.current can be initialized only onece"); 084 LanguageType.current = current; 085 } 086 }; 087 public static final String DEFAULT_TEMPLATE_FOLDER = "thrift"; 088 public static final String DEFAULT_LANGUAGE = "JAVA"; 089 /** refClass 的默认值 */ 090 public static final Class<?> DEF_REF_CLASS = Object.class; 091 private static final String NO_REF_CLASS = ""; 092 private Map<Class<?>, Class<?>> interfaceClasses; 093 private TaskType taskType; 094 private LanguageType languageType; 095 private String thriftClientPackage; 096 private final PropertiesConfiguration config = new PropertiesConfiguration(); 097 public static final ThriftServiceDecoratorConfiguration INSTANCE = new ThriftServiceDecoratorConfiguration(); 098 private ThriftServiceDecoratorConfiguration() { 099 super(); 100 // 指定模板文件夹 101 this.defaultValue.setProperty(TEMPLATE_FOLDER_OPTION_LONG, DEFAULT_TEMPLATE_FOLDER); 102 // 指定refClass的默认值,避免默认值为{@code null} 103 this.defaultValue.setProperty(REFERENCE_CLASS_OPTION_LONG,NO_REF_CLASS); 104 // 指定refClass的默认值,避免默认值为{@code null} 105 this.defaultValue.setProperty(THRIFT_CLIENT_PKG_OPTION_LONG,""); 106 // 指定refClass的默认值,避免默认值为{@code null} 107 this.defaultValue.setProperty(LANGUAGE_OPTION_LONG,DEFAULT_LANGUAGE); 108 // 指定CONFIG的默认值,避免默认值为{@code null} 109 this.defaultValue.setProperty(CONFIG_OPTION_LONG,null); 110 } 111 112 @Override 113 public void loadConfig(Options options, CommandLine cmd) throws ParseException { 114 super.loadConfig(options, cmd); 115 try { 116 List<Class<?>> interfaceList = toClassArray((String) getProperty(INTERFACE_CLASS_OPTION_LONG)); 117 List<Class<?>> refList = toClassArray((String) getProperty(REFERENCE_CLASS_OPTION_LONG)); 118 this.thriftClientPackage = (String)getProperty(THRIFT_CLIENT_PKG_OPTION_LONG); 119 if(refList.size()>0 && refList.size() != interfaceList.size()){ 120 throw new ParseException("mismatch number interface class and reference class"); 121 } 122 interfaceClasses = Maps.newLinkedHashMap(); 123 for(int i = 0 ;i < interfaceList.size() ; ++i){ 124 Class<?> key = interfaceList.get(i); 125 if(interfaceList.get(i)!=DEF_REF_CLASS){ 126 try{ 127 Class<?> value = refList.get(i); 128 interfaceClasses.put(key, value); 129 }catch(IndexOutOfBoundsException e){ 130 interfaceClasses.put(key, DEF_REF_CLASS); 131 } 132 } 133 } 134 if(interfaceList.isEmpty()){ 135 throw new ParseException("NOT FOUND VALID interface class define"); 136 } 137 } catch (ClassNotFoundException e) { 138 throw new ParseException("ClassNotFoundException:"+e.getMessage()); 139 } 140 try{ 141 taskType = TaskType.valueOf((String) getProperty(TASK_TYPE_OPTION_LONG)); 142 if((taskType == TaskType.CLIENT || taskType == TaskType.CLIENT_THRIFTY) && this.thriftClientPackage.isEmpty()){ 143 throw new IllegalArgumentException(String.format("must set param :%s",THRIFT_CLIENT_PKG_OPTION_LONG)); 144 } 145 }catch(IllegalArgumentException e){ 146 throw new ParseException(e.getMessage()); 147 } 148 try{ 149 languageType = LanguageType.valueOf((String) getProperty(LANGUAGE_OPTION_LONG)); 150 LanguageType.setCurrent(languageType); 151 }catch(IllegalArgumentException e){ 152 throw new ParseException(e.getMessage()); 153 } 154 if(hasProperty(CONFIG_OPTION_LONG)){ 155 File configFile = new File((String) getProperty(CONFIG_OPTION_LONG)); 156 checkArgument(configFile.isFile() && configFile.getName().endsWith(".properties"), 157 "%s must be a .properties file",CONFIG_OPTION_LONG); 158 try { 159 // 指定文件编码方式,否则properties文件读取中文会是乱码,要求文件编码是UTF-8 160 FileBasedConfigurationBuilder.setDefaultEncoding(PropertiesConfiguration.class, ENCODING); 161 new FileHandler(config).load(configFile); 162 } catch (Exception e) { 163 Throwables.throwIfUnchecked(e); 164 throw new RuntimeException(e); 165 } 166 } 167 } 168 169 private List<Class<?>> toClassArray(String input) throws ClassNotFoundException{ 170 String[] classNames = input.split(","); 171 List<Class<?>>result = Lists.newArrayList(); 172 for(String name:classNames){ 173 result.add(name.isEmpty()? DEF_REF_CLASS : Class.forName(name)); 174 } 175 return result; 176 } 177 178 public Map<Class<?>, Class<?>> getInterfaceClasses() { 179 return interfaceClasses; 180 } 181 182 public TaskType getTaskType() { 183 return taskType; 184 } 185 186 public LanguageType getLanguageType() { 187 return languageType; 188 } 189 190 @Override 191 public String getTemplateFolder() { 192 String folder = super.getTemplateFolder(); 193 StringBuilder sb = new StringBuilder(folder); 194 if(DEFAULT_TEMPLATE_FOLDER.equals(folder)){ 195 sb.append(getLanguageType().postfix); 196 } 197 sb.append("/").append(getTaskType().folder); 198 return sb.toString(); 199 } 200 201 public String getThriftClientPackage() { 202 return thriftClientPackage; 203 } 204 public CodeWriter getCodeWriter(){ 205 return this.getLanguageType().getCodeWriter(getOutputLocation()); 206 } 207 208 /** 209 * @return config 210 */ 211 public Configuration getConfig() { 212 return config; 213 } 214}