001 /** 002 * Copyright 2004-2014 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.opensource.org/licenses/ecl2.php 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 String viewId = "KS-" + infoClass + "-AdminLookupView"; 094 out.println(""); 095 out.incrementIndent(); 096 out.indentPrintln("<import resource=\"classpath:ks-" + infoClass + "-dictionary.xml\"/>"); 097 out.indentPrintln("<import resource=\"classpath:UifKSDefinitions.xml\"/>"); 098 out.indentPrintln("<!-- **********************************************"); 099 out.indentPrintln("Paste this link below into WEB-INF ksAdminLinks.tag or ksMaintenance.tag in KS with Rice Bundled etc"); 100 out.indentPrintln(""); 101 out.indentPrintln("<li><portal:portalLink displayTitle=\"true\" title=\"" + xmlType.getName() + " Lookup\"" 102 + " url=\"${ConfigProperties.application.url}/kr-krad/lookup?methodToCall=start" 103 + "&dataObjectClassName=" + xmlType.getJavaPackage() + "." + infoClass + "" 104 + "&viewId=" + viewId 105 + "&returnLocation=${ConfigProperties.application.url}/portal.do&hideReturnLink=true\" /></li>"); 106 out.indentPrintln ("Also..."); 107 out.indentPrintln("Paste bean definition below into the list of dataDictionaryPackages in StudentSpringBeans.xml "); 108 out.indentPrintln ("<value>classpath:" + fullDirectoryPath + "/" + fileName + "</value>"); 109 out.indentPrintln("********************************************** -->"); 110 out.indentPrintln("<!-- LookupView -->"); 111 out.indentPrintln("<bean id=\"" + viewId + "\" parent=\"KS-Uif-LookupView\""); 112 out.incrementIndent(); 113 out.indentPrintln("p:title=\"" + xmlType.getName() + " Lookup\""); 114 out.indentPrintln("p:header.headerText=\"" + xmlType.getName() + " Lookup\""); 115 out.indentPrintln("p:dataObjectClassName=\"" + xmlType.getJavaPackage() + "." + infoClass + "\""); 116 out.indentPrintln("p:viewHelperServiceClass=\"" + lookupable + "\">"); 117 out.indentPrintln(""); 118 out.indentPrintln("<property name=\"criteriaFields\">"); 119 out.incrementIndent(); 120 out.indentPrintln("<list>"); 121 out.incrementIndent(); 122 out.indentPrintln("<bean parent=\"Uif-LookupCriteriaInputField\" p:propertyName=\"keywordSearch\""); 123 out.indentPrintln(" p:label=\"Keyword(s)\""); 124 out.indentPrintln(" p:helpSummary=\"Searches fields like name and description to see if they contain the keyword\" />"); 125 this.writeFieldsToSearchOn (xmlType, new Stack<XmlType>(), ""); 126 out.indentPrintln("<bean parent=\"Uif-LookupCriteriaInputField\" p:propertyName=\"maxResultsToReturn\""); 127 out.indentPrintln(" p:label=\"Max. Results\""); 128 out.indentPrintln(" p:defaultValue=\"50\""); 129 out.indentPrintln(" p:helpSummary=\"The maximum number of results to return from the query, leave null to not limit the results\" />"); 130 out.decrementIndent(); 131 out.indentPrintln("</list>"); 132 out.decrementIndent(); 133 out.indentPrintln("</property>"); 134 out.indentPrintln("<property name=\"resultFields\">"); 135 out.indentPrintln(" <list>"); 136 for (MessageStructure ms : this.getFieldsToShowOnLookup()) { 137 String fieldName = GetterSetterNameCalculator.calcInitLower(ms.getShortName()); 138 out.indentPrint(" <bean parent=\"Uif-DataField\" p:propertyName=\"" + fieldName + "\""); 139 if (ms.isPrimaryKey()) { 140 out.println(">"); 141 out.indentPrintln(" <property name=\"inquiry\">"); 142 out.indentPrintln(" <bean parent=\"Uif-Inquiry\" p:dataObjectClassName=\"" + xmlType.getJavaPackage() + "." + xmlType.getName() + "\" p:inquiryParameters=\"" + ms.getShortName() + "\" />"); 143 out.indentPrintln(" </property>"); 144 out.indentPrintln(" </bean>"); 145 } else if (AdminUiInquiryViewBeanWriter.shouldDoLookup (ms.getLookup())) { 146 147 out.println(">"); 148 Lookup lookup = ms.getLookup(); 149 XmlType msType = finder.findXmlType(lookup.getXmlTypeName()); 150 MessageStructure pk = this.getPrimaryKey(ms.getLookup().getXmlTypeName()); 151 out.indentPrintln(" <property name=\"inquiry\">"); 152 out.indentPrintln(" <bean parent=\"Uif-Inquiry\" p:dataObjectClassName=\"" 153 + msType.getJavaPackage() + "." + msType.getName() 154 + "\" p:inquiryParameters=\"" + fieldName + ":" + pk.getShortName() + "\" />"); 155 out.indentPrintln(" </property>"); 156 out.indentPrintln(" </bean>"); 157 } else { 158 out.println(" />"); 159 } 160 } 161 out.indentPrintln(" </list>"); 162 out.indentPrintln("</property>"); 163 out.decrementIndent(); 164 out.indentPrintln("</bean>"); 165 out.indentPrintln(""); 166 out.decrementIndent(); 167 out.indentPrintln("</beans>"); 168 } 169 170 171 private MessageStructure getPrimaryKey(String xmlTypeName) { 172 for (MessageStructure ms : finder.findMessageStructures(xmlTypeName)) { 173 if (ms.isPrimaryKey()) { 174 return ms; 175 } 176 } 177 throw new NullPointerException ("could not find primary key for " + xmlTypeName); 178 } 179 180 181 private void writeFieldsToSearchOn(XmlType type, Stack<XmlType> parents, String prefix) { 182 // avoid recursion 183 if (parents.contains(type)) { 184 return; 185 } 186 parents.push(type); 187 for (MessageStructure ms : finder.findMessageStructures(type.getName())) { 188 String fieldName = GetterSetterNameCalculator.calcInitLower(ms.getShortName()); 189 if (!prefix.isEmpty()) { 190 fieldName = prefix + "." + fieldName; 191 } 192 String fieldNameCamel = GetterSetterNameCalculator.dot2Camel(fieldName); 193 if (ms.getShortName().equalsIgnoreCase("versionInd")) { 194 out.indentPrintln("<!-- TODO: deal with seaching on the version indicator which is a string in the contract but a number in the database -->"); 195 continue; 196 } 197 if (ms.getType().equalsIgnoreCase("AttributeInfoList")) { 198 out.indentPrintln("<!-- TODO: deal with dynamic attributes -->"); 199 continue; 200 } 201 if (ms.getShortName ().equalsIgnoreCase("name")) { 202 out.indentPrintln("<!-- skip name because keyword searching should cover it -->"); 203 continue; 204 } 205 if (ms.getShortName ().equalsIgnoreCase("descr")) { 206 out.indentPrintln("<!-- skip description because keyword searching should cover it -->"); 207 continue; 208 } 209 if (ms.getType().endsWith("List")) { 210 out.indentPrintln("<!-- TODO: deal with " + fieldName + " which is a List -->"); 211 continue; 212 } 213 XmlType fieldType = finder.findXmlType(ms.getType()); 214 if (fieldType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) { 215 // complex sub-types such as rich text 216 this.writeFieldsToSearchOn(fieldType, parents, fieldName); 217 continue; 218 } 219 if (!ms.getType().equalsIgnoreCase("String")) { 220 out.indentPrintln("<!-- TODO: deal with " + fieldName + " which is a " + ms.getType() + " -->"); 221 continue; 222 } 223 224 out.indentPrint("<bean parent=\"Uif-LookupCriteriaInputField\" p:propertyName=\"" + fieldName + "\""); 225 if (!AdminUiInquiryViewBeanWriter.shouldDoLookup (ms.getLookup())) { 226 out.println(" />"); 227 continue; 228 } 229 out.println(">"); 230 out.incrementIndent(); 231 XmlType msType = finder.findXmlType(ms.getLookup().getXmlTypeName()); 232 if (msType == null) { 233 throw new NullPointerException ("Processing lookup for: " + type.getName () 234 + ms.getName() 235 + " lookup=" + ms.getLookup().getXmlTypeName()); 236 } 237 out.indentPrintln("<property name=\"quickfinder\">"); 238 out.incrementIndent(); 239 out.indentPrintln("<bean parent=\"Uif-QuickFinder\" p:dataObjectClassName=\"" + msType.getJavaPackage() + "." + msType.getName() + "\""); 240 MessageStructure pk = this.getPrimaryKey(ms.getLookup().getXmlTypeName()); 241 if (pk == null) { 242 throw new NullPointerException("could not find primary key for " + ms.getId()); 243 } 244 out.indentPrintln("p:fieldConversions=\"" + pk.getShortName() + ":" + fieldName + "\" />"); 245 out.decrementIndent(); 246 out.indentPrintln("</property>"); 247 out.decrementIndent(); 248 out.indentPrintln("</bean>"); 249 } 250 parents.pop(); 251 } 252 253 private List<MessageStructure> getFieldsToSearchOn() { 254 List<MessageStructure> list = new ArrayList<MessageStructure>(); 255 for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) { 256 // lists of values cannot be displayed within a list of values 257 if (ms.getType().endsWith("List")) { 258 continue; 259 } 260 if (ms.getType().endsWith("List")) { 261 continue; 262 } 263 XmlType msType = finder.findXmlType(ms.getType()); 264 // just show fields on the main object for now don't dive down into complex fields 265 if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) { 266 continue; 267 } 268 } 269 return list; 270 } 271 272 private List<MessageStructure> getFieldsToShowOnLookup() { 273 List<MessageStructure> list = new ArrayList<MessageStructure>(); 274 for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) { 275 // lists of values cannot be displayed within a list of values 276 if (ms.getType().endsWith("List")) { 277 continue; 278 } 279 XmlType msType = finder.findXmlType(ms.getType()); 280 // just show fields on the main object for now don't dive down into complex fields 281 if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) { 282 continue; 283 } 284 list.add(ms); 285 } 286 return list; 287 } 288 289 private void initXmlWriter() { 290 String infoClass = GetterSetterNameCalculator.calcInitUpper(xmlType.getName()); 291 String serviceClass = GetterSetterNameCalculator.calcInitUpper(service.getName()); 292 String serviceVar = GetterSetterNameCalculator.calcInitLower(service.getName()); 293 String serviceContract = service.getImplProject() + "." + service.getName(); 294 295 fullDirectoryPath = AdminUiLookupableWriter.calcPackage(servKey, rootPackage, xmlType).replace('.', '/'); 296 fileName = infoClass + "AdminLookupView.xml"; 297 298 File dir = new File(this.directory); 299 300 if (!dir.exists()) { 301 if (!dir.mkdirs()) { 302 throw new IllegalStateException("Could not create directory " 303 + this.directory); 304 } 305 } 306 307 String dirStr = this.directory + "/" + "resources" + "/" + fullDirectoryPath; 308 File dirFile = new File(dirStr); 309 if (!dirFile.exists()) { 310 if (!dirFile.mkdirs()) { 311 throw new IllegalStateException( 312 "Could not create directory " + dirStr); 313 } 314 } 315 try { 316 PrintStream out = new PrintStream(new FileOutputStream( 317 dirStr + "/" 318 + fileName, false)); 319 log.info("AdminUILookupViewBeanWriter: writing " + dirStr + "/" + fileName); 320 this.out = new XmlWriter(out, 0); 321 } catch (FileNotFoundException ex) { 322 throw new IllegalStateException(ex); 323 } 324 } 325 326 private void writeBoilerPlate() { 327 out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); 328 out.println("<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""); 329 out.println(" xmlns:p=\"http://www.springframework.org/schema/p\""); 330 out.println(" xsi:schemaLocation=\"http://www.springframework.org/schema/beans"); 331 out.println(" http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\">"); 332 out.println(" <!--"); 333 out.println(" Copyright 2007-2012 The Kuali Foundation"); 334 out.println(""); 335 out.println(" Licensed under the Educational Community License, Version 2.0 (the \"License\");"); 336 out.println(" you may not use this file except in compliance with the License."); 337 out.println(" You may obtain a copy of the License at"); 338 out.println(""); 339 out.println(" http://www.opensource.org/licenses/ecl2.php"); 340 out.println(""); 341 out.println(" Unless required by applicable law or agreed to in writing, software"); 342 out.println(" distributed under the License is distributed on an \"AS IS\" BASIS,"); 343 out.println(" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied."); 344 out.println(" See the License for the specific language governing permissions and"); 345 out.println(" limitations under the License."); 346 out.println(" -->"); 347 348 } 349 }