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.remote.impl.mojo;
017    
018    import java.util.ArrayList;
019    import java.util.List;
020    import org.kuali.student.contract.model.Service;
021    
022    import org.kuali.student.contract.model.ServiceContractModel;
023    import org.kuali.student.contract.model.ServiceMethod;
024    import org.kuali.student.contract.model.ServiceMethodError;
025    import org.kuali.student.contract.model.ServiceMethodParameter;
026    import org.kuali.student.contract.model.XmlType;
027    import org.kuali.student.contract.model.util.ModelFinder;
028    import org.kuali.student.contract.writer.JavaClassWriter;
029    import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
030    import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator;
031    import org.kuali.student.contract.writer.service.ServiceExceptionWriter;
032    
033    /**
034     *
035     * @author nwright
036     */
037    public class RemoteImplServiceWriter extends JavaClassWriter {
038    
039        private ServiceContractModel model;
040        private ModelFinder finder;
041        private String directory;
042        private String rootPackage;
043        private String servKey;
044        private List<ServiceMethod> methods;
045    
046        public RemoteImplServiceWriter(ServiceContractModel model,
047                String directory,
048                String rootPackage,
049                String servKey,
050                List<ServiceMethod> methods) {
051            super(directory + "/main/java", calcPackage(servKey, rootPackage), calcClassName(servKey));
052            this.model = model;
053            this.finder = new ModelFinder(model);
054            this.directory = directory;
055            this.rootPackage = rootPackage;
056            this.servKey = servKey;
057            this.methods = methods;
058        }
059    
060        public static String calcPackage(String servKey, String rootPackage) {
061    //        String pack = rootPackage + "." + servKey.toLowerCase() + ".";
062    //  StringBuffer buf = new StringBuffer (service.getVersion ().length ());
063    //  for (int i = 0; i < service.getVersion ().length (); i ++)
064    //  {
065    //   char c = service.getVersion ().charAt (i);
066    //   c = Character.toLowerCase (c);
067    //   if (Character.isLetter (c))
068    //   {
069    //    buf.append (c);
070    //    continue;
071    //   }
072    //   if (Character.isDigit (c))
073    //   {
074    //    buf.append (c);
075    //   }
076    //  }
077    //  pack = pack + buf.toString ();
078    //        pack = pack + "service.decorators";
079    //        return pack;
080            return rootPackage;
081        }
082    
083        public static String calcClassName(String servKey) {
084            return GetterSetterNameCalculator.calcInitUpper(servKey + "ServiceRemoteImpl");
085        }
086    
087        public static String calcDecoratorClassName(String servKey) {
088            return GetterSetterNameCalculator.calcInitUpper(servKey + "ServiceDecorator");
089        }
090    
091        private static enum MethodType {
092    
093            VALIDATE, CREATE, UPDATE
094        };
095    
096        private MethodType calcMethodType(ServiceMethod method) {
097            if (method.getName().startsWith("validate")) {
098                return MethodType.VALIDATE;
099            }
100            if (method.getName().startsWith("create")) {
101                return MethodType.CREATE;
102            }
103            if (method.getName().startsWith("update")) {
104                return MethodType.UPDATE;
105            }
106            return null;
107        }
108    
109        /**
110         * Write out the entire file
111         *
112         * @param out
113         */
114        public void write() {
115            indentPrint("public class " + calcClassName(servKey));
116            println(" extends " + calcDecoratorClassName(servKey));
117            // TODO: figure out how to add import for the decorator
118            openBrace();
119            writeHostUrlGetterSetter();
120    
121            indentPrintln("//");
122            indentPrintln("// Have to override and check for null because of a bug in CXF 2.3.8 our current version");
123            indentPrintln("// It was fixed in 2.6.1 but 2.3.8 still renders empty lists as null when transported by soap");
124            indentPrintln("// see http://stackoverflow.com/questions/11384986/apache-cxf-web-services-problems");
125            indentPrintln("//");
126            for (ServiceMethod method : methods) {
127                if (!method.getReturnValue().getType().endsWith("List")) {
128                    continue;
129                }
130    
131                indentPrintln("");
132    //            indentPrintln("/**");
133    //            indentPrintWrappedComment(method.getDescription());
134    //            indentPrintln("* ");
135    //            for (ServiceMethodParameter param : method.getParameters()) {
136    //                indentPrintWrappedComment("@param " + param.getName() + " - "
137    //                        + param.getType() + " - "
138    //                        + param.getDescription());
139    //            }
140    //            indentPrintWrappedComment("@return " + method.getReturnValue().
141    //                    getDescription());
142    //            indentPrintln("*/");
143                indentPrintln("@Override");
144                String type = method.getReturnValue().getType();
145                String realType = stripList(type);
146                indentPrint("public " + calcType(type, realType) + " " + method.getName()
147                        + "(");
148                // now do parameters
149                String comma = "";
150                for (ServiceMethodParameter param : method.getParameters()) {
151                    type = param.getType();
152                    realType = stripList(type);
153                    print(comma);
154                    print(calcType(type, realType));
155                    print(" ");
156                    print(param.getName());
157                    comma = ", ";
158                }
159                println(")");
160                // now do exceptions
161                comma = "throws ";
162                incrementIndent();
163                for (ServiceMethodError error : method.getErrors()) {
164                    indentPrint(comma);
165                    String exceptionClassName = calcExceptionClassName(error);
166                    String exceptionPackageName = this.calcExceptionPackageName(error);
167                    println(exceptionClassName);
168                    this.importsAdd(exceptionPackageName + "." + exceptionClassName);
169                    comma = "      ,";
170                }
171                decrementIndent();
172                openBrace();
173                type = method.getReturnValue().getType();
174                realType = stripList(type);
175                XmlType retValXmlType = finder.findXmlType(realType);
176                importsAdd(retValXmlType.getJavaPackage() + "." + retValXmlType.getName());
177                indentPrint("List<" + retValXmlType.getName() + "> list = this.getNextDecorator ()." + method.getName() + "(");
178                comma = "";
179                for (ServiceMethodParameter param : method.getParameters()) {
180                    type = param.getType();
181                    realType = stripList(type);
182                    print(comma);
183                    print(param.getName());
184                    comma = ", ";
185                }
186                println(");");
187                indentPrintln("if (list == null)");
188                openBrace();
189                importsAdd(ArrayList.class.getName());
190                indentPrintln("return new ArrayList<" + retValXmlType.getName() + "> ();");
191                closeBrace();
192                indentPrintln("return list;");
193                closeBrace();
194            }
195            closeBrace();
196    
197            this.writeJavaClassAndImportsOutToFile();
198            this.getOut().close();
199        }
200    
201        private String calcType(String type, String realType) {
202            XmlType t = finder.findXmlType(this.stripList(type));
203            return MessageStructureTypeCalculator.calculate(this, model, type, realType,
204                    t.getJavaPackage());
205        }
206    
207        private String stripList(String str) {
208            return GetterSetterNameCalculator.stripList(str);
209        }
210    
211        private String calcExceptionClassName(ServiceMethodError error) {
212            if (error.getClassName() == null) {
213                return ServiceExceptionWriter.calcClassName(error.getType());
214            }
215            return error.getClassName();
216        }
217    
218        private String calcExceptionPackageName(ServiceMethodError error) {
219            if (error.getClassName() == null) {
220                return ServiceExceptionWriter.calcPackage(rootPackage);
221            }
222            return error.getPackageName();
223        }
224    
225        private void writeHostUrlGetterSetter() {
226    
227            String initUpper = GetterSetterNameCalculator.calcInitUpper(servKey);
228    
229            indentPrintln("private String hostUrl;");
230            println("");
231            indentPrintln("public String getHostUrl()");
232            openBrace();
233            indentPrintln("return hostUrl;");
234            closeBrace();
235            indentPrintln("public void setHostUrl(String hostUrl)");
236            openBrace();
237            indentPrintln("this.hostUrl = hostUrl;");
238            indentPrintln("if (hostUrl == null)");
239            openBrace();
240            indentPrintln("this.setNextDecorator(null);");
241            indentPrintln("return;");
242            closeBrace();
243            indentPrintln("URL wsdlURL;");
244            indentPrintln("try");
245            openBrace();
246            String constantsFile = initUpper + "ServiceConstants";
247            // TODO: figure out how to add import for the service constants
248            indentPrintln("String urlStr = hostUrl + \"/services/\" + " + constantsFile + ".SERVICE_NAME_LOCAL_PART + \"?wsdl\";");
249            indentPrintln("wsdlURL = new URL(urlStr);");
250            closeBrace();
251            indentPrintln("catch (MalformedURLException ex)");
252            openBrace();
253            indentPrintln("throw new IllegalArgumentException(ex);");
254            closeBrace();
255    
256            importsAdd("java.net.MalformedURLException");
257            importsAdd("java.net.URL");
258            importsAdd("javax.xml.namespace.QName");
259            importsAdd("javax.xml.ws.Service");
260            Service service = finder.findService(servKey);
261            importsAdd(service.getImplProject() + "." + service.getName());
262    
263            indentPrintln("QName qname = new QName(" + constantsFile + ".NAMESPACE, " + constantsFile + ".SERVICE_NAME_LOCAL_PART);");
264            indentPrintln("Service factory = Service.create(wsdlURL, qname);");
265            indentPrintln(service.getName() + " port = factory.getPort(" + service.getName() + ".class);");
266            indentPrintln("this.setNextDecorator(port);");
267            closeBrace();
268    
269        }
270    }