View Javadoc

1   /*
2    * Copyright 2009 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may	obtain a copy of the License at
7    *
8    * 	http://www.osedu.org/licenses/ECL-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.student.remote.impl.mojo;
17  
18  import java.util.ArrayList;
19  import java.util.HashSet;
20  import java.util.List;
21  import java.util.Set;
22  import java.util.Stack;
23  import org.kuali.rice.core.api.criteria.Predicate;
24  import org.kuali.rice.core.api.criteria.PredicateFactory;
25  import org.kuali.rice.core.api.criteria.QueryByCriteria;
26  import org.kuali.student.admin.ui.mojo.AdminUiLookupableWriter;
27  import org.kuali.student.contract.model.MessageStructure;
28  import org.kuali.student.contract.model.Service;
29  
30  import org.kuali.student.contract.model.ServiceContractModel;
31  import org.kuali.student.contract.model.ServiceMethod;
32  import org.kuali.student.contract.model.ServiceMethodError;
33  import org.kuali.student.contract.model.XmlType;
34  import org.kuali.student.contract.model.util.ModelFinder;
35  import org.kuali.student.contract.writer.JavaClassWriter;
36  import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
37  import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator;
38  import org.kuali.student.contract.writer.service.ServiceExceptionWriter;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  /**
43   *
44   * @author nwright
45   */
46  public class RemoteImplServiceTestWriter extends JavaClassWriter {
47  
48      private static final Logger log = LoggerFactory.getLogger(RemoteImplServiceTestWriter.class);
49      private ServiceContractModel model;
50      private ModelFinder finder;
51      private String directory;
52      private String rootPackage;
53      private String servKey;
54      private List<ServiceMethod> methods;
55      private Service service;
56  
57      public RemoteImplServiceTestWriter(ServiceContractModel model,
58              String directory,
59              String rootPackage,
60              String servKey,
61              List<ServiceMethod> methods) {
62          super(directory + "/test/java", calcPackage(servKey, rootPackage), calcClassName(servKey));
63          this.model = model;
64          this.finder = new ModelFinder(model);
65          this.directory = directory;
66          this.rootPackage = rootPackage;
67          this.servKey = servKey;
68          this.service = finder.findService(servKey);
69          this.methods = methods;
70      }
71  
72      public static String calcPackage(String servKey, String rootPackage) {
73  //        String pack = rootPackage + "." + servKey.toLowerCase() + ".";
74  //  StringBuffer buf = new StringBuffer (service.getVersion ().length ());
75  //  for (int i = 0; i < service.getVersion ().length (); i ++)
76  //  {
77  //   char c = service.getVersion ().charAt (i);
78  //   c = Character.toLowerCase (c);
79  //   if (Character.isLetter (c))
80  //   {
81  //    buf.append (c);
82  //    continue;
83  //   }
84  //   if (Character.isDigit (c))
85  //   {
86  //    buf.append (c);
87  //   }
88  //  }
89  //  pack = pack + buf.toString ();
90  //        pack = pack + "service.decorators";
91  //        return pack;
92          return rootPackage;
93      }
94  
95      public static String calcClassName(String servKey) {
96          return GetterSetterNameCalculator.calcInitUpper(servKey + "ServiceRemoteImplTest");
97      }
98  
99      public static String calcDecoratorClassName(String servKey) {
100         return GetterSetterNameCalculator.calcInitUpper(servKey + "ServiceDecorator");
101     }
102 
103     private static enum MethodType {
104 
105         VALIDATE, CREATE, UPDATE
106     };
107 
108     private MethodType calcMethodType(ServiceMethod method) {
109         if (method.getName().startsWith("validate")) {
110             return MethodType.VALIDATE;
111         }
112         if (method.getName().startsWith("create")) {
113             return MethodType.CREATE;
114         }
115         if (method.getName().startsWith("update")) {
116             return MethodType.UPDATE;
117         }
118         return null;
119     }
120 
121     /**
122      * Write out the entire file
123      *
124      * @param out
125      */
126     public void write() {
127         String serviceName = service.getName();
128         indentPrintln("//@Ignore");
129         indentPrintln("public class " + calcClassName(servKey));
130         // TODO: figure out how to add import for the decorator
131         openBrace();
132         importsAdd("org.junit.*");
133         XmlType contextInfo = finder.findXmlType("contextInfo");
134         importsAdd(contextInfo.getJavaPackage() + "." + contextInfo.getName());
135         indentPrintln("private static ContextInfo contextInfo;");
136 
137         indentPrintln("private static " + serviceName + "RemoteImpl service;");
138         indentPrintln("");
139         indentPrintln("");
140         indentPrintln("@BeforeClass");
141         indentPrintln("public static void setUpClass() throws Exception");
142         openBrace();
143         indentPrintln("service = new " + serviceName + "RemoteImpl();");
144         indentPrintln("service.setHostUrl(RemoteServiceConstants.ENV2_URL);");
145         indentPrintln("//service.setHostUrl(RemoteServiceConstants.LOCAL_HOST_EMBEDDED_URL);");
146         indentPrintln("contextInfo = new ContextInfo();");
147         indentPrintln("contextInfo.setPrincipalId(\"TESTUSER\");");
148         closeBrace();
149         indentPrintln("");
150         indentPrintln("@AfterClass");
151         indentPrintln("public static void tearDownClass() throws Exception");
152         openBrace();
153         closeBrace();
154         indentPrintln("");
155         indentPrintln("@Before");
156         indentPrintln("public void setUp()");
157         openBrace();
158         closeBrace();
159         indentPrintln("");
160         indentPrintln("@After");
161         indentPrintln("public void tearDown()");
162         openBrace();
163         closeBrace();
164         indentPrintln("");
165 
166 
167         Set<XmlType> types = this.getMainXmlTypesUsedByService(methods);
168         if (types.isEmpty()) {
169             log.warn("No types defined for servKey: " + servKey);
170             return;
171         }
172         // the main servKey
173         log.info("Generating search by criteria tests for " + types.size() + " in " + servKey);
174         for (XmlType type : types) {
175             this.writeTestMethodsForXmlType(type);
176         }
177         closeBrace();
178 
179         this.writeJavaClassAndImportsOutToFile();
180         this.getOut().close();
181     }
182 
183     private void writeTestMethodsForXmlType(XmlType xmlType) {
184         ServiceMethod searchMethod = AdminUiLookupableWriter.findSearchMethod(xmlType, methods);
185         String infoClass = GetterSetterNameCalculator.calcInitUpper(xmlType.getName());
186         importsAdd(xmlType.getJavaPackage() + "." + xmlType.getName());
187         indentPrintln("");
188         indentPrintln("@Test");
189         indentPrintln("public void testSearch" + infoClass + "All () throws Exception");
190         openBrace();
191         importsAdd(QueryByCriteria.class.getName());
192         importsAdd(Predicate.class.getName());
193         importsAdd(PredicateFactory.class.getName());
194         indentPrintln("QueryByCriteria.Builder qBuilder = QueryByCriteria.Builder.create();");
195         indentPrintln("qBuilder.setMaxResults (30);");
196         importsAdd(List.class.getName());
197         indentPrintln("List<" + infoClass + "> infos = service." + searchMethod.getName() + "(qBuilder.build(), contextInfo);");
198         closeBrace();
199 
200 
201         indentPrintln("");
202         indentPrintln("@Test");
203         indentPrintln("public void testSearch" + infoClass + "KeywordSearch () throws Exception");
204         openBrace();
205         importsAdd(QueryByCriteria.class.getName());
206         importsAdd(Predicate.class.getName());
207         importsAdd(PredicateFactory.class.getName());
208         indentPrintln("QueryByCriteria.Builder qBuilder = QueryByCriteria.Builder.create();");
209         importsAdd (ArrayList.class.getName());
210         indentPrintln("List<Predicate> pList = new ArrayList<Predicate>();");
211         indentPrintln("pList.add(PredicateFactory.equal(\"keywordSearch\", \"xyzzysomethingnothingmatches\"));");
212         indentPrintln("qBuilder.setPredicates(PredicateFactory.and(pList.toArray(new Predicate[pList.size()])));");
213         indentPrintln("qBuilder.setMaxResults (30);");
214         importsAdd(List.class.getName());
215         indentPrintln("List<" + infoClass + "> infos = service." + searchMethod.getName() + "(qBuilder.build(), contextInfo);");
216         closeBrace();
217 
218         this.writeFieldTests(infoClass, searchMethod, xmlType, new Stack<XmlType>(), "");
219     }
220 
221     private void writeFieldTests(String infoClass, ServiceMethod searchMethod, XmlType type, Stack<XmlType> parents, String prefix) {
222         // avoid recursion
223         if (parents.contains(type)) {
224             return;
225         }
226         parents.push(type);
227         for (MessageStructure ms : finder.findMessageStructures(type.getName())) {
228             String fieldName = GetterSetterNameCalculator.calcInitLower(ms.getShortName());
229             if (!prefix.isEmpty()) {
230                 fieldName = prefix + "." + fieldName;
231             }
232             String fieldNameCamel = GetterSetterNameCalculator.dot2Camel(fieldName);
233             if (ms.getShortName().equalsIgnoreCase("versionInd")) {
234                 indentPrintln("// TODO: deal with seaching on the version indicator which is a string in the contract but a number in the database");
235                 continue;
236             }
237             if (ms.getType().equalsIgnoreCase("AttributeInfoList")) {
238                 indentPrintln("// TODO: deal with dynamic attributes");
239                 continue;
240             }
241             if (ms.getType().endsWith("List")) {
242                 indentPrintln("// TODO: deal with  " + fieldName + " which is a List");
243                 continue;
244             }
245             XmlType fieldType = finder.findXmlType(ms.getType());
246             if (fieldType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
247                 // complex sub-types such as rich text 
248                 this.writeFieldTests(infoClass, searchMethod, fieldType, parents, fieldName);
249                 continue;
250             }
251             if (!ms.getType().equalsIgnoreCase("String")) {
252                 indentPrintln("// TODO: deal with  " + fieldName + " which is a " + ms.getType());
253                 continue;
254             }
255 
256             indentPrintln("");
257             indentPrintln("@Test");
258             indentPrintln("public void testSearch" + infoClass + "By" + fieldNameCamel + " () throws Exception");
259             openBrace();
260             indentPrintln("QueryByCriteria.Builder qBuilder = QueryByCriteria.Builder.create();");
261             indentPrintln("List<Predicate> pList = new ArrayList<Predicate>();");
262             indentPrintln("pList.add(PredicateFactory.equal(\"" + fieldName + "\", \"xyzzysomethingnothingmatches\"));");
263             indentPrintln("qBuilder.setPredicates(PredicateFactory.and(pList.toArray(new Predicate[pList.size()])));");
264             indentPrintln("qBuilder.setMaxResults (30);");
265             indentPrintln("List<" + infoClass + "> infos = service." + searchMethod.getName() + "(qBuilder.build(), contextInfo);");
266             closeBrace();
267 
268         }
269         parents.pop();
270     }
271 
272     private String calcType(String type, String realType) {
273         XmlType t = finder.findXmlType(this.stripList(type));
274         return MessageStructureTypeCalculator.calculate(this, model, type, realType,
275                 t.getJavaPackage());
276     }
277 
278     private String stripList(String str) {
279         return GetterSetterNameCalculator.stripList(str);
280     }
281 
282     private String calcExceptionClassName(ServiceMethodError error) {
283         if (error.getClassName() == null) {
284             return ServiceExceptionWriter.calcClassName(error.getType());
285         }
286         return error.getClassName();
287     }
288 
289     private String calcExceptionPackageName(ServiceMethodError error) {
290         if (error.getClassName() == null) {
291             return ServiceExceptionWriter.calcPackage(rootPackage);
292         }
293         return error.getPackageName();
294     }
295 
296     private Set<XmlType> getMainXmlTypesUsedByService(List<ServiceMethod> methods) {
297         Set<XmlType> set = new HashSet();
298         for (ServiceMethod method : methods) {
299             if (method.getReturnValue().getType().endsWith("List")) {
300                 continue;
301             }
302             XmlType returnType = finder.findXmlType(method.getReturnValue().getType());
303             if (returnType == null) {
304                 continue;
305             }
306             if (!returnType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
307                 continue;
308             }
309             // TYPE only should show up on type service
310             if (returnType.getName().equalsIgnoreCase("TypeInfo")) {
311                 if (!servKey.equalsIgnoreCase("type")) {
312                     continue;
313                 }
314             }
315             // State only should show up on type service
316             if (returnType.getName().equalsIgnoreCase("StateInfo")) {
317                 if (!servKey.equalsIgnoreCase("state")) {
318                     continue;
319                 }
320             }
321 //            if (method.getName().startsWith("create")) {
322 //                set.add(returnType);
323 //                continue;
324 //            }
325 //            if (method.getName().startsWith("update")) {
326 //                set.add(returnType);
327 //                continue;
328 //            }
329             if (method.getName().startsWith("get")) {
330                 if (method.getParameters().size() == 2) {
331                     if (method.getParameters().get(0).getType().equalsIgnoreCase("String")) {
332                         set.add(returnType);
333                         continue;
334                     }
335                 }
336             }
337         }
338         return set;
339     }
340 
341     private List<MessageStructure> getFieldsToSearchOn(XmlType xmlType) {
342         List<MessageStructure> list = new ArrayList<MessageStructure>();
343         for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
344             XmlType msType = finder.findXmlType(ms.getType());
345             // TODO: dive down into complex sub-types 
346             if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
347                 continue;
348             }
349             list.add(ms);
350         }
351         return list;
352     }
353 }