001 /* 002 * Copyright 2009 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.osedu.org/licenses/ECL-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.kuali.student.admin.ui.mojo; 017 018 import java.io.File; 019 import java.io.FileNotFoundException; 020 import java.io.FileOutputStream; 021 import java.io.PrintStream; 022 import java.util.ArrayList; 023 import java.util.List; 024 import java.util.Stack; 025 import org.kuali.student.contract.model.Lookup; 026 import org.kuali.student.contract.model.MessageStructure; 027 import org.kuali.student.contract.model.Service; 028 029 import org.kuali.student.contract.model.ServiceContractModel; 030 import org.kuali.student.contract.model.ServiceMethod; 031 import org.kuali.student.contract.model.XmlType; 032 import org.kuali.student.contract.model.impl.ServiceContractModelQDoxLoader; 033 import org.kuali.student.contract.model.util.ModelFinder; 034 import org.kuali.student.contract.writer.XmlWriter; 035 import org.kuali.student.contract.writer.service.GetterSetterNameCalculator; 036 import org.slf4j.Logger; 037 import org.slf4j.LoggerFactory; 038 039 /** 040 * 041 * @author nwright 042 */ 043 public class AdminUiLookupViewBeanWriter { 044 045 private static final Logger log = LoggerFactory.getLogger(AdminUiLookupViewBeanWriter.class); 046 047 private ServiceContractModel model; 048 private ModelFinder finder; 049 private String directory; 050 private String rootPackage; 051 private String servKey; 052 private Service service; 053 private XmlType xmlType; 054 private List<ServiceMethod> methods; 055 private XmlWriter out; 056 String fileName; 057 String fullDirectoryPath; 058 059 public AdminUiLookupViewBeanWriter(ServiceContractModel model, 060 String directory, 061 String rootPackage, 062 String servKey, 063 XmlType xmlType, 064 List<ServiceMethod> methods) { 065 this.model = model; 066 this.finder = new ModelFinder(model); 067 this.directory = directory; 068 this.rootPackage = rootPackage; 069 this.servKey = servKey; 070 service = finder.findService(servKey); 071 this.xmlType = xmlType; 072 this.methods = methods; 073 } 074 075 /** 076 * Write out the entire file 077 * 078 * @param out 079 */ 080 public void write() { 081 initXmlWriter(); 082 writeBoilerPlate(); 083 writeBean(); 084 } 085 086 private void writeBean() { 087 String infoClass = GetterSetterNameCalculator.calcInitUpper(xmlType.getName()); 088 String serviceClass = GetterSetterNameCalculator.calcInitUpper(service.getName()); 089 String serviceVar = GetterSetterNameCalculator.calcInitLower(service.getName()); 090 String serviceContract = service.getImplProject() + "." + service.getName(); 091 String lookupable = AdminUiLookupableWriter.calcPackage(servKey, rootPackage, xmlType) + "." 092 + AdminUiLookupableWriter.calcClassName(servKey, xmlType); 093 out.println(""); 094 out.incrementIndent(); 095 out.indentPrintln("<import resource=\"classpath:ks-" + infoClass + "-dictionary.xml\"/>"); 096 out.indentPrintln("<import resource=\"classpath:UifKSDefinitions.xml\"/>"); 097 out.indentPrintln("<!-- **********************************************"); 098 out.indentPrintln("Paste this link below into WEB-INF ksAdminLinks.tag"); 099 out.indentPrintln("<li><portal:portalLink displayTitle=\"true\" title=\"" + xmlType.getName() + " Lookup\"" 100 + "url=\"${ConfigProperties.application.url}/kr-krad/lookup?methodToCall=start" 101 + "&dataObjectClassName=" + xmlType.getJavaPackage() + "." + infoClass + "" 102 + "&viewId=" + fileName 103 + "&returnLocation=${ConfigProperties.application.url}/portal.do&hideReturnLink=true\" /></li>"); 104 out.indentPrintln ("Also..."); 105 out.indentPrintln("Paste bean definition below into the list of dataDictionaryPackages of org.kuali.rice.krad.bo.ModuleConfiguration "); 106 out.indentPrintln ("<value>classpath:" + fullDirectoryPath + "/" + fileName + "</value>"); 107 out.indentPrintln("********************************************** -->"); 108 out.indentPrintln("<!-- LookupView -->"); 109 out.indentPrintln("<bean id=\"KS-" + infoClass + "-AdminLookupView\" parent=\"KS-Uif-LookupView\""); 110 out.incrementIndent(); 111 out.indentPrintln("p:title=\"" + xmlType.getName() + " Lookup\""); 112 out.indentPrintln("p:header.headerText=\"" + xmlType.getName() + " Lookup\""); 113 out.indentPrintln("p:dataObjectClassName=\"" + xmlType.getJavaPackage() + "." + infoClass + "\""); 114 out.indentPrintln("p:viewHelperServiceClass=\"" + lookupable + "\">"); 115 out.indentPrintln(""); 116 out.indentPrintln("<property name=\"criteriaFields\">"); 117 out.incrementIndent(); 118 out.indentPrintln("<list>"); 119 out.incrementIndent(); 120 out.indentPrintln("<bean parent=\"Uif-LookupCriteriaInputField\" p:propertyName=\"keywordSearch\""); 121 out.indentPrintln(" p:label=\"Keyword(s)\""); 122 out.indentPrintln(" p:helpSummary=\"Searches fields like name and description to see if they contain the keyword\" />"); 123 this.writeFieldsToSearchOn (xmlType, new Stack<XmlType>(), ""); 124 out.indentPrintln("<bean parent=\"Uif-LookupCriteriaInputField\" p:propertyName=\"maxResultsToReturn\""); 125 out.indentPrintln(" p:label=\"Max. Results\""); 126 out.indentPrintln(" p:defaultValue=\"50\""); 127 out.indentPrintln(" p:helpSummary=\"The maximum number of results to return from the query, leave null to not limit the results\" />"); 128 out.decrementIndent(); 129 out.indentPrintln("</list>"); 130 out.decrementIndent(); 131 out.indentPrintln("</property>"); 132 out.indentPrintln("<property name=\"resultFields\">"); 133 out.indentPrintln(" <list>"); 134 for (MessageStructure ms : this.getFieldsToShowOnLookup()) { 135 String fieldName = GetterSetterNameCalculator.calcInitLower(ms.getShortName()); 136 out.indentPrint(" <bean parent=\"Uif-DataField\" p:propertyName=\"" + fieldName + "\""); 137 if (ms.isPrimaryKey()) { 138 out.println(">"); 139 out.indentPrintln(" <property name=\"inquiry\">"); 140 out.indentPrintln(" <bean parent=\"Uif-Inquiry\" p:dataObjectClassName=\"" + xmlType.getJavaPackage() + "." + xmlType.getName() + "\" p:inquiryParameters=\"" + ms.getShortName() + "\" />"); 141 out.indentPrintln(" </property>"); 142 out.indentPrintln(" </bean>"); 143 } else if (AdminUiInquiryViewBeanWriter.shouldDoLookup (ms.getLookup())) { 144 145 out.println(">"); 146 Lookup lookup = ms.getLookup(); 147 XmlType msType = finder.findXmlType(lookup.getXmlTypeName()); 148 MessageStructure pk = this.getPrimaryKey(ms.getLookup().getXmlTypeName()); 149 out.indentPrintln(" <property name=\"inquiry\">"); 150 out.indentPrintln(" <bean parent=\"Uif-Inquiry\" p:dataObjectClassName=\"" 151 + msType.getJavaPackage() + "." + msType.getName() 152 + "\" p:inquiryParameters=\"" + fieldName + ":" + pk.getShortName() + "\" />"); 153 out.indentPrintln(" </property>"); 154 out.indentPrintln(" </bean>"); 155 } else { 156 out.println(" />"); 157 } 158 } 159 out.indentPrintln(" </list>"); 160 out.indentPrintln("</property>"); 161 out.decrementIndent(); 162 out.indentPrintln("</bean>"); 163 out.indentPrintln(""); 164 out.decrementIndent(); 165 out.indentPrintln("</beans>"); 166 } 167 168 169 private MessageStructure getPrimaryKey(String xmlTypeName) { 170 for (MessageStructure ms : finder.findMessageStructures(xmlTypeName)) { 171 if (ms.isPrimaryKey()) { 172 return ms; 173 } 174 } 175 throw new NullPointerException ("could not find primary key for " + xmlTypeName); 176 } 177 178 179 private void writeFieldsToSearchOn(XmlType type, Stack<XmlType> parents, String prefix) { 180 // avoid recursion 181 if (parents.contains(type)) { 182 return; 183 } 184 parents.push(type); 185 for (MessageStructure ms : finder.findMessageStructures(type.getName())) { 186 String fieldName = GetterSetterNameCalculator.calcInitLower(ms.getShortName()); 187 if (!prefix.isEmpty()) { 188 fieldName = prefix + "." + fieldName; 189 } 190 String fieldNameCamel = GetterSetterNameCalculator.dot2Camel(fieldName); 191 if (ms.getShortName().equalsIgnoreCase("versionInd")) { 192 out.indentPrintln("<!-- TODO: deal with seaching on the version indicator which is a string in the contract but a number in the database -->"); 193 continue; 194 } 195 if (ms.getType().equalsIgnoreCase("AttributeInfoList")) { 196 out.indentPrintln("<!-- TODO: deal with dynamic attributes -->"); 197 continue; 198 } 199 if (ms.getShortName ().equalsIgnoreCase("name")) { 200 out.indentPrintln("<!-- skip name because keyword searching should cover it -->"); 201 continue; 202 } 203 if (ms.getShortName ().equalsIgnoreCase("descr")) { 204 out.indentPrintln("<!-- skip description because keyword searching should cover it -->"); 205 continue; 206 } 207 if (ms.getType().endsWith("List")) { 208 out.indentPrintln("<!-- TODO: deal with " + fieldName + " which is a List -->"); 209 continue; 210 } 211 XmlType fieldType = finder.findXmlType(ms.getType()); 212 if (fieldType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) { 213 // complex sub-types such as rich text 214 this.writeFieldsToSearchOn(fieldType, parents, fieldName); 215 continue; 216 } 217 if (!ms.getType().equalsIgnoreCase("String")) { 218 out.indentPrintln("<!-- TODO: deal with " + fieldName + " which is a " + ms.getType() + " -->"); 219 continue; 220 } 221 222 out.indentPrint("<bean parent=\"Uif-LookupCriteriaInputField\" p:propertyName=\"" + fieldName + "\""); 223 if (!AdminUiInquiryViewBeanWriter.shouldDoLookup (ms.getLookup())) { 224 out.println(" />"); 225 continue; 226 } 227 out.println(""); 228 out.incrementIndent(); 229 XmlType msType = finder.findXmlType(ms.getLookup().getXmlTypeName()); 230 if (msType == null) { 231 throw new NullPointerException ("Processing lookup for: " + type.getName () 232 + ms.getName() 233 + " lookup=" + ms.getLookup().getXmlTypeName()); 234 } 235 out.indentPrintln("p:quickfinder.dataObjectClassName=\"" + msType.getJavaPackage() + "." + msType.getName() + "\""); 236 MessageStructure pk = this.getPrimaryKey(ms.getLookup().getXmlTypeName()); 237 if (pk == null) { 238 throw new NullPointerException("could not find primary key for " + ms.getId()); 239 } 240 out.indentPrintln("p:quickfinder.fieldConversions=\"" + pk.getShortName() + ":" + fieldName + "\""); 241 out.indentPrintln("/>"); 242 out.decrementIndent(); 243 } 244 parents.pop(); 245 } 246 247 private List<MessageStructure> getFieldsToSearchOn() { 248 List<MessageStructure> list = new ArrayList<MessageStructure>(); 249 for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) { 250 // lists of values cannot be displayed within a list of values 251 if (ms.getType().endsWith("List")) { 252 continue; 253 } 254 if (ms.getType().endsWith("List")) { 255 continue; 256 } 257 XmlType msType = finder.findXmlType(ms.getType()); 258 // just show fields on the main object for now don't dive down into complex fields 259 if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) { 260 continue; 261 } 262 } 263 return list; 264 } 265 266 private List<MessageStructure> getFieldsToShowOnLookup() { 267 List<MessageStructure> list = new ArrayList<MessageStructure>(); 268 for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) { 269 // lists of values cannot be displayed within a list of values 270 if (ms.getType().endsWith("List")) { 271 continue; 272 } 273 XmlType msType = finder.findXmlType(ms.getType()); 274 // just show fields on the main object for now don't dive down into complex fields 275 if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) { 276 continue; 277 } 278 list.add(ms); 279 } 280 return list; 281 } 282 283 private void initXmlWriter() { 284 String infoClass = GetterSetterNameCalculator.calcInitUpper(xmlType.getName()); 285 String serviceClass = GetterSetterNameCalculator.calcInitUpper(service.getName()); 286 String serviceVar = GetterSetterNameCalculator.calcInitLower(service.getName()); 287 String serviceContract = service.getImplProject() + "." + service.getName(); 288 289 fullDirectoryPath = AdminUiLookupableWriter.calcPackage(servKey, rootPackage, xmlType).replace('.', '/'); 290 fileName = infoClass + "AdminLookupView.xml"; 291 292 File dir = new File(this.directory); 293 294 if (!dir.exists()) { 295 if (!dir.mkdirs()) { 296 throw new IllegalStateException("Could not create directory " 297 + this.directory); 298 } 299 } 300 301 String dirStr = this.directory + "/" + "resources" + "/" + fullDirectoryPath; 302 File dirFile = new File(dirStr); 303 if (!dirFile.exists()) { 304 if (!dirFile.mkdirs()) { 305 throw new IllegalStateException( 306 "Could not create directory " + dirStr); 307 } 308 } 309 try { 310 PrintStream out = new PrintStream(new FileOutputStream( 311 dirStr + "/" 312 + fileName, false)); 313 log.info("AdminUILookupViewBeanWriter: writing " + dirStr + "/" + fileName); 314 this.out = new XmlWriter(out, 0); 315 } catch (FileNotFoundException ex) { 316 throw new IllegalStateException(ex); 317 } 318 } 319 320 private void writeBoilerPlate() { 321 out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 322 out.println("<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); 323 out.println(" xmlns:p=\"http://www.springframework.org/schema/p\""); 324 out.println(" xsi:schemaLocation=\"http://www.springframework.org/schema/beans"); 325 out.println(" http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\">"); 326 out.println(" <!--"); 327 out.println(" Copyright 2007-2012 The Kuali Foundation"); 328 out.println(""); 329 out.println(" Licensed under the Educational Community License, Version 2.0 (the \"License\");"); 330 out.println(" you may not use this file except in compliance with the License."); 331 out.println(" You may obtain a copy of the License at"); 332 out.println(""); 333 out.println(" http://www.opensource.org/licenses/ecl2.php"); 334 out.println(""); 335 out.println(" Unless required by applicable law or agreed to in writing, software"); 336 out.println(" distributed under the License is distributed on an \"AS IS\" BASIS,"); 337 out.println(" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."); 338 out.println(" See the License for the specific language governing permissions and"); 339 out.println(" limitations under the License."); 340 out.println(" -->"); 341 342 } 343 }