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 */
016package org.kuali.student.remote.impl.mojo;
017
018import java.util.ArrayList;
019import java.util.List;
020import org.kuali.student.contract.model.Service;
021
022import org.kuali.student.contract.model.ServiceContractModel;
023import org.kuali.student.contract.model.ServiceMethod;
024import org.kuali.student.contract.model.ServiceMethodError;
025import org.kuali.student.contract.model.ServiceMethodParameter;
026import org.kuali.student.contract.model.XmlType;
027import org.kuali.student.contract.model.util.ModelFinder;
028import org.kuali.student.contract.writer.JavaClassWriter;
029import org.kuali.student.contract.writer.service.GetterSetterNameCalculator;
030import org.kuali.student.contract.writer.service.MessageStructureTypeCalculator;
031import org.kuali.student.contract.writer.service.ServiceExceptionWriter;
032
033/**
034 *
035 * @author nwright
036 */
037public 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        String name = GetterSetterNameCalculator.calcInitUpper(servKey + "ServiceRemoteImpl");
085        if (name.startsWith("RICE.")) {
086            name = name.substring("RICE.".length());
087        }
088        return name;
089    }
090
091    public static String calcDecoratorClassName(String servKey) {
092        String name = GetterSetterNameCalculator.calcInitUpper(servKey + "ServiceDecorator");
093        if (name.startsWith("RICE.")) {
094            name = name.substring("RICE.".length());
095        }
096        return name;
097    }
098
099    private static enum MethodType {
100
101        VALIDATE, CREATE, UPDATE
102    };
103
104    private MethodType calcMethodType(ServiceMethod method) {
105        if (method.getName().startsWith("validate")) {
106            return MethodType.VALIDATE;
107        }
108        if (method.getName().startsWith("create")) {
109            return MethodType.CREATE;
110        }
111        if (method.getName().startsWith("update")) {
112            return MethodType.UPDATE;
113        }
114        return null;
115    }
116
117    /**
118     * Write out the entire file
119     *
120     * @param out
121     */
122    public void write() {
123        indentPrint("public class " + calcClassName(servKey));
124        println(" extends " + calcDecoratorClassName(servKey));
125        // TODO: figure out how to add import for the decorator
126        openBrace();
127        writeBiolerPlate();
128        indentPrintln("//");
129        indentPrintln("// Have to override and check each method that returns a list for null");
130        indentPrintln("// This is because SOAP/JAXB renders and empty list as null ");
131        indentPrintln("// but our contract standard says we ALWAYS return an empty list");
132        indentPrintln("//");
133        for (ServiceMethod method : methods) {
134            if (!method.getReturnValue().getType().endsWith("List")) {
135                continue;
136            }
137
138            indentPrintln("");
139//            indentPrintln("/**");
140//            indentPrintWrappedComment(method.getDescription());
141//            indentPrintln("* ");
142//            for (ServiceMethodParameter param : method.getParameters()) {
143//                indentPrintWrappedComment("@param " + param.getName() + " - "
144//                        + param.getType() + " - "
145//                        + param.getDescription());
146//            }
147//            indentPrintWrappedComment("@return " + method.getReturnValue().
148//                    getDescription());
149//            indentPrintln("*/");
150            indentPrintln("@Override");
151            String type = method.getReturnValue().getType();
152            String realType = stripList(type);
153            indentPrint("public " + calcType(type, realType) + " " + method.getName()
154                    + "(");
155            // now do parameters
156            String comma = "";
157            for (ServiceMethodParameter param : method.getParameters()) {
158                type = param.getType();
159                realType = stripList(type);
160                print(comma);
161                print(calcType(type, realType));
162                print(" ");
163                print(param.getName());
164                comma = ", ";
165            }
166            println(")");
167            // now do exceptions
168            comma = "throws ";
169            incrementIndent();
170            for (ServiceMethodError error : method.getErrors()) {
171                indentPrint(comma);
172                String exceptionClassName = calcExceptionClassName(error);
173                String exceptionPackageName = this.calcExceptionPackageName(error);
174                println(exceptionClassName);
175                this.importsAdd(exceptionPackageName + "." + exceptionClassName);
176                comma = "      ,";
177            }
178            decrementIndent();
179            openBrace();
180            type = method.getReturnValue().getType();
181            realType = stripList(type);
182            XmlType retValXmlType = finder.findXmlType(realType);
183            importsAdd(retValXmlType.getJavaPackage() + "." + retValXmlType.getName());
184            indentPrint("List<" + retValXmlType.getName() + "> list = this.getNextDecorator ()." + method.getName() + "(");
185            comma = "";
186            for (ServiceMethodParameter param : method.getParameters()) {
187                type = param.getType();
188                realType = stripList(type);
189                print(comma);
190                print(param.getName());
191                comma = ", ";
192            }
193            println(");");
194            indentPrintln("if (list == null)");
195            openBrace();
196            importsAdd(ArrayList.class.getName());
197            indentPrintln("return new ArrayList<" + retValXmlType.getName() + "> ();");
198            closeBrace();
199            indentPrintln("return list;");
200            closeBrace();
201        }
202        closeBrace();
203
204        this.writeJavaClassAndImportsOutToFile();
205        this.getOut().close();
206    }
207
208    private String calcType(String type, String realType) {
209        XmlType t = finder.findXmlType(this.stripList(type));
210        return MessageStructureTypeCalculator.calculate(this, model, type, realType,
211                t.getJavaPackage());
212    }
213
214    private String stripList(String str) {
215        return GetterSetterNameCalculator.stripList(str);
216    }
217
218    private String calcExceptionClassName(ServiceMethodError error) {
219        if (error.getClassName() == null) {
220            return ServiceExceptionWriter.calcClassName(error.getType());
221        }
222        return error.getClassName();
223    }
224
225    private String calcExceptionPackageName(ServiceMethodError error) {
226        if (error.getClassName() == null) {
227            return ServiceExceptionWriter.calcPackage(rootPackage);
228        }
229        return error.getPackageName();
230    }
231
232    private void writeBiolerPlate() {
233
234        String initUpperServKey = GetterSetterNameCalculator.calcInitUpper(servKey);
235        if (initUpperServKey.startsWith("RICE.")) {
236            initUpperServKey = initUpperServKey.substring("RICE.".length());
237        }
238
239        // TODO: figure out how to add import for the service constants
240        importsAdd("java.net.MalformedURLException");
241        importsAdd("java.net.URL");
242        importsAdd("javax.xml.namespace.QName");
243        importsAdd("javax.xml.ws.Service");
244        Service service = finder.findService(servKey);
245        importsAdd(service.getImplProject() + "." + service.getName());
246
247        indentPrintln("private String hostUrl = null;");
248        indentPrintln("private String servicesUrlFragment = \"/services/\";");
249        indentPrintln("private String serviceNameLocalPart = " + initUpperServKey + "ServiceConstants.SERVICE_NAME_LOCAL_PART;");
250        indentPrintln("private String namespace = " + initUpperServKey + "ServiceConstants.NAMESPACE;");
251        indentPrintln("private URL wsdlUrl = null;");
252        println("");
253        indentPrintln("public String getHostUrl() {");
254        indentPrintln("    // check if explicitly configured, manually for testing or via spring");
255        indentPrintln("    if (this.hostUrl != null) {");
256        indentPrintln("        return hostUrl;");
257        indentPrintln("    }");
258        indentPrintln("    // check for a specific url for this service (not all services may be hosted from the same place)");
259        indentPrintln("    Properties config = ConfigContext.getCurrentContextConfig().getProperties();");
260        indentPrintln("    this.hostUrl = config.getProperty(\"remote.service.host.url." + servKey.toLowerCase() + "\");");
261        indentPrintln("    if (this.hostUrl != null) {");
262        indentPrintln("        return this.hostUrl;");
263        indentPrintln("    }");
264        indentPrintln("    // check for the default for all remote services");
265        indentPrintln("    this.hostUrl = config.getProperty(\"remote.service.host.url\");");
266        indentPrintln("    if (this.hostUrl != null) {");
267        indentPrintln("        return this.hostUrl;");
268        indentPrintln("    }");
269        indentPrintln("    throw new IllegalArgumentException(\"No host url configured\");");
270        indentPrintln("}");
271        println("");
272        indentPrintln("public void setHostUrl(String hostUrl) {");
273        indentPrintln("    this.hostUrl = hostUrl;");
274        indentPrintln("}");
275        println("");
276        indentPrintln("public URL getWsdlUrl() {");
277        indentPrintln("    if (this.wsdlUrl == null) {");
278        indentPrintln("        String urlString = this.getHostUrl() + this.getServicesUrlFragment() + this.getServiceNameLocalPart() + \"?wsdl\";");
279        indentPrintln("        try {");
280        indentPrintln("            this.wsdlUrl = new URL(urlString);");
281        indentPrintln("        } catch (MalformedURLException ex) {");
282        indentPrintln("            throw new IllegalArgumentException(urlString, ex);");
283        indentPrintln("        }");
284        indentPrintln("    }");
285        indentPrintln("    return wsdlUrl;");
286        indentPrintln("}");
287        println("");
288        indentPrintln("public void setWsdlUrl(URL wsdlUrl) {");
289        indentPrintln("    this.wsdlUrl = wsdlUrl;");
290        indentPrintln("}");
291        println("");
292        indentPrintln("public String getServiceNameLocalPart() {");
293        indentPrintln("    return serviceNameLocalPart;");
294        indentPrintln("}");
295        println("");
296        indentPrintln("public void setServiceNameLocalPart(String serviceNameLocalPart) {");
297        indentPrintln("    this.serviceNameLocalPart = serviceNameLocalPart;");
298        indentPrintln("}");
299        println("");
300        indentPrintln("public String getServicesUrlFragment() {");
301        indentPrintln("    return servicesUrlFragment;");
302        indentPrintln("}");
303        println("");
304        indentPrintln("public void setServicesUrlFragment(String servicesUrlFragment) {");
305        indentPrintln("    this.servicesUrlFragment = servicesUrlFragment;");
306        indentPrintln("}");
307        println("");
308        indentPrintln("public String getNamespace() {");
309        indentPrintln("    return namespace;");
310        indentPrintln("}");
311        println("");
312        indentPrintln("public void setNamespace(String namespace) {");
313        indentPrintln("    this.namespace = namespace;");
314        indentPrintln("}");
315        println("");
316        indentPrintln("public void init() {");
317        indentPrintln("    QName qname = new QName(this.getNamespace(), this.getServiceNameLocalPart());");
318        indentPrintln("    Service factory = Service.create(this.getWsdlUrl(), qname);");
319        indentPrintln("    " + initUpperServKey + "Service port = factory.getPort(" + initUpperServKey + "Service.class);");
320        indentPrintln("    this.setNextDecorator(port);");
321        indentPrintln("}");
322        println("");
323        indentPrintln("private boolean hasBeenIntialized = false;");
324        println("");
325        indentPrintln("@Override");
326        indentPrintln("public " + initUpperServKey + "Service getNextDecorator() throws OperationFailedException {");
327        indentPrintln("    if (!this.hasBeenIntialized) {");
328        indentPrintln("        this.hasBeenIntialized = true;");
329        indentPrintln("        this.init();");
330        indentPrintln("    }");
331        indentPrintln("    return super.getNextDecorator();");
332        indentPrintln("}");
333        println("");
334
335    }
336}