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=\"KSLookupView\"");
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=\"30\"");
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.doLookup (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.doLookup (ms.getLookup())) {
224                    out.println(" />");
225                    continue;
226                }
227                out.println("");
228                out.incrementIndent();
229                XmlType msType = finder.findXmlType(ms.getLookup().getXmlTypeName());
230                out.indentPrintln("p:quickfinder.dataObjectClassName=\"" + msType.getJavaPackage() + "." + msType.getName() + "\"");
231                MessageStructure pk = this.getPrimaryKey(ms.getLookup().getXmlTypeName());
232                if (pk == null) {
233                    throw new NullPointerException("could not find primary key for " + ms.getId());
234                }
235                out.indentPrintln("p:quickfinder.fieldConversions=\"" + pk.getShortName() + ":" + fieldName + "\"");
236                out.indentPrintln("/>");
237                out.decrementIndent();
238            }
239            parents.pop();
240        }
241        
242        private List<MessageStructure> getFieldsToSearchOn() {
243            List<MessageStructure> list = new ArrayList<MessageStructure>();
244            for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
245                // lists of values cannot be displayed within a list of values
246                if (ms.getType().endsWith("List")) {
247                    continue;
248                }
249                if (ms.getType().endsWith("List")) {
250                    continue;
251                }
252                XmlType msType = finder.findXmlType(ms.getType());
253                // just show fields on the main object for now don't dive down into complex fields
254                if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
255                    continue;
256                }
257            }
258            return list;
259        }
260    
261        private List<MessageStructure> getFieldsToShowOnLookup() {
262            List<MessageStructure> list = new ArrayList<MessageStructure>();
263            for (MessageStructure ms : finder.findMessageStructures(xmlType.getName())) {
264                // lists of values cannot be displayed within a list of values
265                if (ms.getType().endsWith("List")) {
266                    continue;
267                }
268                XmlType msType = finder.findXmlType(ms.getType());
269                // just show fields on the main object for now don't dive down into complex fields
270                if (msType.getPrimitive().equalsIgnoreCase(XmlType.COMPLEX)) {
271                    continue;
272                }
273                list.add(ms);
274            }
275            return list;
276        }
277    
278        private void initXmlWriter() {
279            String infoClass = GetterSetterNameCalculator.calcInitUpper(xmlType.getName());
280            String serviceClass = GetterSetterNameCalculator.calcInitUpper(service.getName());
281            String serviceVar = GetterSetterNameCalculator.calcInitLower(service.getName());
282            String serviceContract = service.getImplProject() + "." + service.getName();
283    
284            fullDirectoryPath = AdminUiLookupableWriter.calcPackage(servKey, rootPackage, xmlType).replace('.', '/');
285            fileName = infoClass + "AdminLookupView.xml";
286    
287            File dir = new File(this.directory);
288    
289            if (!dir.exists()) {
290                if (!dir.mkdirs()) {
291                    throw new IllegalStateException("Could not create directory "
292                            + this.directory);
293                }
294            }
295    
296            String dirStr = this.directory + "/" + "resources" + "/" + fullDirectoryPath;
297            File dirFile = new File(dirStr);
298            if (!dirFile.exists()) {
299                if (!dirFile.mkdirs()) {
300                    throw new IllegalStateException(
301                            "Could not create directory " + dirStr);
302                }
303            }
304            try {
305                PrintStream out = new PrintStream(new FileOutputStream(
306                        dirStr + "/"
307                        + fileName, false));
308                log.info("AdminUILookupViewBeanWriter: writing " + dirStr + "/" + fileName);
309                this.out = new XmlWriter(out, 0);
310            } catch (FileNotFoundException ex) {
311                throw new IllegalStateException(ex);
312            }
313        }
314    
315        private void writeBoilerPlate() {
316            out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
317            out.println("<beans xmlns=\"http://www.springframework.org/schema/beans\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
318            out.println("       xmlns:p=\"http://www.springframework.org/schema/p\"");
319            out.println("       xsi:schemaLocation=\"http://www.springframework.org/schema/beans");
320            out.println("                    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd\">");
321            out.println("    <!--");
322            out.println("     Copyright 2007-2012 The Kuali Foundation");
323            out.println("");
324            out.println("     Licensed under the Educational Community License, Version 2.0 (the \"License\");");
325            out.println("     you may not use this file except in compliance with the License.");
326            out.println("     You may obtain a copy of the License at");
327            out.println("");
328            out.println("     http://www.opensource.org/licenses/ecl2.php");
329            out.println("");
330            out.println("     Unless required by applicable law or agreed to in writing, software");
331            out.println("     distributed under the License is distributed on an \"AS IS\" BASIS,");
332            out.println("     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.");
333            out.println("     See the License for the specific language governing permissions and");
334            out.println("     limitations under the License.");
335            out.println("    -->");
336    
337        }
338    }