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    }