/** * Create a file that contains a single worker thread class. All child worker classes are * generated on a per-operation basis for each and every RPC method defined in the WSDL document. * * <p>This method will trigger the class generation and add all required Java imports to the * source file. * * @param operation FOperation object from WSDL parser * @throws Exception Error during code generation */ private void createWorkerThreadFile(final FOperation operation) throws Exception { String rpcMethodName = WorkerThreadGenerator.firstLetterCapital(operation.getOperationName()); JSourceFile jsf = this.workspace .getJava() .getJSourceFile(this.threadWorkerPackageName, rpcMethodName + "Worker"); // Add child worker thread class jsf.add(this.createWorkerThreadClass(operation)); // Add required imports this.addRequiredImport(jsf, "org.slf4j.Logger"); this.addRequiredImport(jsf, "org.slf4j.LoggerFactory"); this.addRequiredImport(jsf, "org.atmosphere.websocket.WebSocket"); this.addRequiredImport( jsf, this.serviceProviderPackageName + "." + this.serviceProviderClassName); this.addRequiredImport(jsf, this.packageName + "." + this.interfaceName); this.addRequiredImport( jsf, this.packageName + "." + JSONMarshallerGenerator.MARSHALLER_CLASS_NAME); // Import server only if required if (null != operation.getOutputMessage()) { this.addRequiredImport(jsf, this.packageName + "." + this.interfaceName); } // Operation has input message if (null != operation.getInputMessage()) { this.addRequiredImport( jsf, this.serviceProviderPackageName + "." + this.getInputMessageName(operation)); } // Operation has output message if (null != operation.getOutputMessage()) { this.addRequiredImport( jsf, this.serviceProviderPackageName + "." + this.getOutputMessageName(operation)); } }
/** * Create code for method body of the run() method that is generated in each of the child thread * worker classes. This function will generate code to unmarshal a request message, call the RPC * method and finally marshal the response message (if RPC method has any output). * * <p>The code generation was moved to this method for better readability. * * @param operation FOperation object from WSDL parser * @param rpcMethodName Name of RPC method * @return Code for method body of run() method */ private String createRunMethodBody(final FOperation operation, final String rpcMethodName) { String methodBody = ""; // Create JSON marshaller object if (null != operation.getInputMessage() || null != operation.getOutputMessage()) { methodBody += String.format( "// Create JSON marshaller\n" + "%s marshaller = new %s();\n\n", JSONMarshallerGenerator.MARSHALLER_CLASS_NAME, JSONMarshallerGenerator.MARSHALLER_CLASS_NAME); } // Operation has input message? if (null != operation.getInputMessage()) { String inputMessageClassName = this.getInputMessageName(operation); // Create code to convert JSON code to a bean object methodBody += String.format( "// Unmarshal JSON code from request\n" + "%s requestBeanObject = (%s)marshaller.jsonToInstance(%s.class, this.requestMessage.payload());\n\n", inputMessageClassName, inputMessageClassName, inputMessageClassName); } // Get name of output message (if any) String outputMessageClassName = ""; if (null != operation.getOutputMessage()) { outputMessageClassName = this.getOutputMessageName(operation); } // Create code to call RPC method methodBody += String.format( "// Call service operation\n" + "LOGGER.info(\"Processing '%s()' request...\");\n" + "%sthis.serviceProvider.%s(%s);", WorkerThreadGenerator.firstLetterLowercase(rpcMethodName), (null != operation.getOutputMessage() ? String.format("%s responseBeanObject = ", outputMessageClassName) : ""), // Method has return value? operation.getOperationName(), (null != operation.getInputMessage() ? "requestBeanObject" : "")); // Method has input? // Operation has output message? if (null != operation.getOutputMessage()) { // Create code to convert bean object to JSON code methodBody += String.format( "\n\n" + "// Marshal bean and create response message\n" + "String jsonResponse = marshaller.instanceToJSON(responseBeanObject);\n" + "%s responseMessage = new %s(this.requestMessage.uuid(), this.requestMessage.method(), jsonResponse);\n\n", this.messageClassFullName, this.messageClassFullName); // Create code to send response methodBody += String.format( "// Send response to client\n" + "LOGGER.info(\"Responding to '%s()' request...\");\n" + "%s.sendMessage(this.webSocket, responseMessage.asString());", WorkerThreadGenerator.firstLetterLowercase(rpcMethodName), this.interfaceName); } // Surround code with try..catch-block methodBody = String.format( "try {\n" + WorkerThreadGenerator.indentCode(methodBody) + "}\n" + "catch (Exception e) {\n" + "\tString jsonResponse = String.format(\"{ \\\"Error\\\": \\\"%%s\\\" }\", e.getMessage());\n" + "\t%s responseMessage = new %s(this.requestMessage.uuid(), this.requestMessage.method(), jsonResponse);\n\n" + "\tLOGGER.error(\"Error: \" + e.getMessage());\n" + "\t%s.sendMessage(this.webSocket, responseMessage.asString());\n" + "}", this.messageClassFullName, this.messageClassFullName, this.interfaceName); return methodBody; }
/** * Create Java class for a single child worker thread. The generated class will be derived from * the base worker thread class and only contains a run() method to start the thread. * * <p>Furthermore, the code includes an inner class that utilizes the Singleton and Builder design * pattern, to create new worker thread objects at runtime. * * @param operation FOperation object from WSDL parser * @return JClass object with child worker thread class * @throws Exception Error during code generation */ private JClass createWorkerThreadClass(final FOperation operation) throws Exception { String rpcMethodName = WorkerThreadGenerator.firstLetterCapital(operation.getOperationName()); String workerClassName = rpcMethodName + "Worker"; // Create worker thread class JClass workerClass = JClass.factory.create(JModifier.PUBLIC, workerClassName); workerClass.setExtends(WORKER_THREAD_CLASS_NAME); workerClass.setComment( new JClassCommentImpl(String.format("The '%s' class.", workerClassName))); LOGGER.debug(String.format("Created '%s' class for child worker thread.", workerClassName)); /** * *************************************************************** Create fields * *************************************************************** */ JField logger = JField.factory.create( JModifier.PRIVATE | JModifier.STATIC | JModifier.FINAL, "Logger", "LOGGER", String.format("LoggerFactory.getLogger(%s.class)", workerClassName)); logger.setComment(new JFieldCommentImpl("Logger object.")); workerClass.add(logger); String builderClassName = workerClassName + "Builder"; JField builder = JField.factory.create( JModifier.PUBLIC | JModifier.STATIC | JModifier.FINAL, builderClassName, "BUILDER", String.format("%s.getInstance()", builderClassName)); builder.setComment( new JFieldCommentImpl( String.format("Builder instance to create new '%s' objects.", workerClassName))); workerClass.add(builder); /** * *************************************************************** Create constructor * *************************************************************** */ JParameter serviceProvider = JParameter.factory.create( JModifier.FINAL, this.serviceProviderClassName, "serviceProvider"); JParameter webSocket = JParameter.factory.create(JModifier.FINAL, "WebSocket", "webSocket"); JParameter requestMessage = JParameter.factory.create(JModifier.FINAL, this.messageClassFullName, "requestMessage"); JMethodSignature jms = JMethodSignature.factory.create(serviceProvider, webSocket, requestMessage); JConstructor constructor = JConstructor.factory.create(JModifier.PRIVATE, workerClassName, jms); constructor.setComment( new JConstructorCommentImpl( String.format("Constructor to create a new '%s' object.", workerClassName))); // Set method body String methodBody = "super(serviceProvider, webSocket, requestMessage);"; constructor.getBody().setSource(methodBody); // Add constructor to class workerClass.add(constructor); /** * *************************************************************** Create run method * *************************************************************** */ JMethod run = JMethod.factory.create(JModifier.PUBLIC, "void", "run"); run.addAnnotation(JMethodAnnotationImpl.OVERRIDE); run.setComment(new JMethodCommentImpl("Run worker thread to handle request.")); // Set method body run.getBody().setSource(this.createRunMethodBody(operation, rpcMethodName)); // Add method to class workerClass.add(run); /** * *************************************************************** Add inner builder class * *************************************************************** */ workerClass.add(this.createInnerBuilderClass(workerClassName)); return workerClass; }