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    }