All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.virtualan.core.soap.SoapEndpointCodeGenerator Maven / Gradle / Ivy

/*
 * Copyright 2020 Virtualan Contributors (https://virtualan.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package io.virtualan.core.soap;

import io.virtualan.core.model.SoapService;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.LoaderClassPath;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.DuplicateMemberException;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.ParameterAnnotationsAttribute;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;
import javax.jws.WebService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;

/**
 * This is Soap Virtual Service .
 *
 * @author  Elan Thangamani
 *
 **/

@Configuration
@Component
@ConditionalOnProperty(name = {"virtualan.soap.package"}, matchIfMissing = true)
public class SoapEndpointCodeGenerator {

  private static Logger log = LoggerFactory.getLogger(SoapEndpointCodeGenerator.class);


  public static Class buildEndpointClass(Map soapWsServices)
      throws CannotCompileException, IOException {
    ClassPool pool = ClassPool.getDefault();
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    pool.insertClassPath(new LoaderClassPath(cl));
    CtClass cc = pool.makeClass("io.virtualan.VirtualanEndpoint");
    addClassAnnotation(cc);
    for (Entry soapWsServiceEntry : soapWsServices.entrySet()) {
      SoapService soapService = soapWsServiceEntry.getValue();
      String methodSignature = generateMethod(soapService);
      CtMethod method = CtMethod.make(methodSignature, cc);

      addParameterAnnotation(cc, method);
      addMethodAnnotation(cc, soapService, method);
    }
    if(log.isDebugEnabled()) {
      cc.getClassFile()
          .write(new DataOutputStream(new FileOutputStream("VirtualanEndpoint.java")));
    }
   return cc.toClass();
  }

  private static void addMethodAnnotation(CtClass cc, SoapService soapService, CtMethod method) {
    Map keyValue = new HashMap();
    keyValue.put("namespace", soapService.getNs());
    keyValue.put("localPart", soapService.getLocalPart());
    ConstPool cpool = cc.getClassFile().getConstPool();
    AnnotationsAttribute attr =
        new AnnotationsAttribute(cpool, AnnotationsAttribute.visibleTag);
    Annotation annot = new Annotation(
        "org.springframework.ws.server.endpoint.annotation.ResponsePayload", cpool);
    attr.addAnnotation(annot);
    Annotation annot1 = new Annotation("io.virtualan.annotation.ApiVirtual", cpool);
    attr.addAnnotation(annot1);
    Annotation annot2 = new Annotation(
        "org.springframework.ws.server.endpoint.annotation.PayloadRoot", cpool);
    keyValue.entrySet().stream().forEach(x -> annot2.addMemberValue(
        x.getKey(),
        new StringMemberValue(x.getValue(), cpool))
    );
    attr.addAnnotation(annot2);
    method.getMethodInfo().addAttribute(attr);
  }

  private static void addParameterAnnotation(CtClass cc, CtMethod method)
      throws DuplicateMemberException {
    ParameterAnnotationsAttribute oldAns = new ParameterAnnotationsAttribute(
        cc.getClassFile().getConstPool(), ParameterAnnotationsAttribute.visibleTag);
    Annotation[][] anAr = new Annotation[1][1];
    anAr[0] = new Annotation[1];
    anAr[0][0] = constructAnnotation(cc.getClassFile().getConstPool(),
        "org.springframework.ws.server.endpoint.annotation.RequestPayload");
    oldAns.setAnnotations(anAr);

    MethodInfo methodInfo = method.getMethodInfo2();
    methodInfo.addAttribute(oldAns);
    cc.getClassFile().addMethod(methodInfo);
  }


  private static Annotation constructAnnotation(ConstPool cp, String annotationName) {
    return new Annotation(annotationName, cp);
  }

  private static String generateMethod(SoapService soapService) {
    StringBuilder sb = new StringBuilder();
    sb.append("public  ")
        .append(soapService.getResponseClassName())
        .append(" ")
        .append(soapService.getMethod())
        .append("( " + soapService.getRequestClassName() + " request " + " )")
        .append("{ return null; }");
    return sb.toString();
  }

  public static void addClassAnnotation(CtClass clazz)  {
    ClassFile cfile = clazz.getClassFile();
    ConstPool cpool = cfile.getConstPool();
    AnnotationsAttribute attr = new AnnotationsAttribute(cpool, AnnotationsAttribute.visibleTag);
    Annotation annot = constructAnnotation(cpool,
        "org.springframework.ws.server.endpoint.annotation.Endpoint");
    Annotation annot2 = constructAnnotation(cpool, "io.virtualan.annotation.VirtualService");
    Annotation annot3 = constructAnnotation(cpool,
        "org.springframework.context.annotation.EnableAspectJAutoProxy");
    attr.addAnnotation(annot2);
    attr.addAnnotation(annot3);
    attr.addAnnotation(annot);
    cfile.addAttribute(attr);
  }


  protected List findMyTypes(String basePackage) {
    List candidates = new ArrayList<>();
    try {
      ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
      MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(
          resourcePatternResolver);
      String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
          resolveBasePackage(basePackage) + "/**/*.class";
      Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
      for (Resource resource : resources) {
        if (resource.isReadable()) {
          MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
          if (isCandidate(metadataReader)) {
            candidates.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
          }
        }
      }
    } catch (IOException | ClassNotFoundException e) {
      log.warn("Unable to load the package : {}"  , basePackage);
    }

    return candidates;
  }

  private String resolveBasePackage(String basePackage) {
    return ClassUtils
        .convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(basePackage));
  }

  private boolean isCandidate(MetadataReader metadataReader) throws ClassNotFoundException {
    try {
      Class c = Class.forName(metadataReader.getClassMetadata().getClassName());
      if (c.getAnnotation(WebService.class) != null) {
        return true;
      }
    } catch (Exception e) {
      log.warn(" isCandidate unexpected error {}", e.getMessage());
    }
    return false;
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy