package org.springframework.roo.addon.ws.addon; import static org.apache.commons.io.IOUtils.LINE_SEPARATOR; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.springframework.roo.addon.ws.annotations.RooSei; import org.springframework.roo.addon.ws.annotations.RooSeiImpl; import org.springframework.roo.addon.ws.annotations.RooWsClients; import org.springframework.roo.addon.ws.annotations.RooWsEndpoints; import org.springframework.roo.addon.ws.annotations.SoapBindingType; import org.springframework.roo.application.config.ApplicationConfigService; import org.springframework.roo.classpath.ModuleFeatureName; import org.springframework.roo.classpath.PhysicalTypeCategory; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.TypeLocationService; import org.springframework.roo.classpath.TypeManagementService; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder; import org.springframework.roo.classpath.details.annotations.ArrayAttributeValue; import org.springframework.roo.classpath.details.annotations.ClassAttributeValue; import org.springframework.roo.classpath.details.annotations.EnumAttributeValue; import org.springframework.roo.classpath.details.annotations.NestedAnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.StringAttributeValue; import org.springframework.roo.classpath.scanner.MemberDetails; import org.springframework.roo.classpath.scanner.MemberDetailsScanner; import org.springframework.roo.model.EnumDetails; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.model.JpaJavaType; import org.springframework.roo.model.RooJavaType; import org.springframework.roo.model.SpringJavaType; import org.springframework.roo.process.manager.FileManager; import org.springframework.roo.project.Dependency; import org.springframework.roo.project.MavenOperations; import org.springframework.roo.project.Path; import org.springframework.roo.project.PathResolver; import org.springframework.roo.project.Plugin; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.project.Property; import org.springframework.roo.project.maven.Pom; import org.springframework.roo.support.logging.HandlerUtils; import org.springframework.roo.support.osgi.ServiceInstaceManager; import org.springframework.roo.support.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** * Implementation of the {@link WsOperations}. It contains all the necessary * implementations for the defined operations in {@link WsOperations}. * * @author Juan Carlos GarcĂ­a * @since 2.0 */ @Component @Service public class WsOperationsImpl implements WsOperations { protected final static Logger LOGGER = HandlerUtils.getLogger(WsOperationsImpl.class); private static final Property CXF_PROPERTY = new Property("cxf.version", "3.1.8"); private static final Dependency CXF_RT_FRONTEND_JAXWS_DEPENDENCY = new Dependency( "org.apache.cxf", "cxf-rt-frontend-jaxws", "${cxf.version}"); private static final Dependency CXF_RT_TRANSPORTS_HTTP_DEPENDENCY = new Dependency( "org.apache.cxf", "cxf-rt-transports-http", "${cxf.version}"); private static final Dependency CXF_STARTER_DEPENDENCY = new Dependency("org.apache.cxf", "cxf-spring-boot-starter-jaxws", "${cxf.version}"); private static final Property TRACEE_PROPERTY = new Property("tracee.version", "1.1.2"); private static final Dependency TRACEE_JAXWS_DEPENDENCY = new Dependency("io.tracee.binding", "tracee-jaxws", "${tracee.version}"); private static final Dependency TRACEE_CXF_DEPENDENCY = new Dependency("io.tracee.binding", "tracee-cxf", "${tracee.version}"); // ------------ OSGi component attributes ---------------- private BundleContext context; private ServiceInstaceManager serviceInstaceManager = new ServiceInstaceManager(); protected void activate(final ComponentContext context) { this.context = context.getBundleContext(); serviceInstaceManager.activate(this.context); } @Override public boolean areWsCommandsAvailable() { return getProjectOperations().isFocusedProjectAvailable(); } @Override public void addWsClient(String wsdlLocation, String endPoint, JavaType configClass, SoapBindingType bindingType, String serviceUrl, String profile) { Validate.notEmpty(wsdlLocation, "ERROR: Provide a valid wsdlLocation"); Validate.notEmpty(endPoint, "ERROR: Provide a valid endPoint"); Validate.notNull(configClass, "ERROR: Provide a valid configClass"); // Check if the configClass is located in an application module if (!isLocatedInApplicationModule(configClass)) { LOGGER.log(Level.INFO, "ERROR: The provided config class is not located in an application module."); return; } // Getting module from the .wsdl file final Pom wsdlModule = getModuleFromWsdlLocation(wsdlLocation); final String wsdlModuleName = wsdlModule.getModuleName(); // Getting the wsdlName without the module final String wsdlName = getWsdlNameWithoutModule(wsdlLocation); // Getting wsdl absolute path from the provided wsdlLocation final String wsdlPath = getWsdlAbsolutePathFromWsdlName(wsdlLocation); // Check if provided .wsdl exists Validate.isTrue(getFileManager().exists(wsdlPath), "ERROR: You must provide an existing .wsdl file."); // To prevent compilation errors, is necessary to include dependencies between // the configClass module and the .wsdl module if (wsdlModuleName != configClass.getModule()) { getProjectOperations().addDependency(configClass.getModule(), new Dependency(wsdlModule.getGroupId(), wsdlModule.getArtifactId(), null)); } // Check if provided configClass exists or should be generated boolean isNewConfigClass = false; ClassOrInterfaceTypeDetails configClassDetails = getTypeLocationService().getTypeDetails(configClass); if (configClassDetails == null) { isNewConfigClass = true; } // If exists, is necessary to check if is a configuration class and if it has some specific profile. // If it have it, it should match with the provided one the provided one if (!isNewConfigClass) { MemberDetails configClassMemberDetails = getMemberDetailsScanner().getMemberDetails(getClass().getName(), configClassDetails); AnnotationMetadata configurationAnnotation = configClassMemberDetails.getAnnotation(SpringJavaType.CONFIGURATION); if (configurationAnnotation == null) { LOGGER .log( Level.INFO, "ERROR: The provided class is not annotated with @Configuration so is not possible to include Web Service client configuration on it." + "Specify other configuration class that contains @Configuration annotation or specify a not existing class to generate it."); return; } if (StringUtils.isNotEmpty(profile)) { AnnotationMetadata profileAnnotation = configClassMemberDetails.getAnnotation(SpringJavaType.PROFILE); if (profileAnnotation != null) { String profiles = (String) profileAnnotation.getAttribute("value").getValue(); String[] definedProfiles = profiles.split(","); boolean profileExists = false; for (String definedProfile : definedProfiles) { if (definedProfile.equals(profile)) { profileExists = true; } } if (!profileExists) { LOGGER.log(Level.INFO, "ERROR: The provided configuration class doesn't work in the provided profile. " + "Use a different configuration class or use a different profile."); return; } } } } // Obtain the service URL from the provided .wsdl file if empty if (StringUtils.isEmpty(serviceUrl)) { serviceUrl = getServiceUrlForEndpointFromWsdlFile(endPoint, wsdlPath); Validate .notEmpty( serviceUrl, "ERROR: It has not been possible to obtain the URL of the service from the provided .wsdl file. Indicate some serviceUrl using --serviceUrl parameter"); } // Obtain the binding type from the provided .wsdl file if empty if (bindingType == null) { bindingType = getBindingTypeFromWsdlFile(wsdlPath); Validate .notNull( bindingType, "ERROR: It has not been possible to obtain the BindingType of the service from the provided .wsdl file. Indicate an specific BindingType using --binding parameter"); } // Always is necessary to obtain the targetNameSpace from the provided .wsdl file String targetNameSpace = getTargetNameSpaceFromWsdlFile(wsdlPath); Validate .notEmpty( targetNameSpace, "ERROR: It has not been possible to obtain the targetNamespace of the service from the provided .wsdl file. Check if your .wsdl file has the correct format."); // Include necessary dependencies and plugins includeDependenciesAndPluginsForWsClient(wsdlName, wsdlModuleName); // Include the necessary properties using the provided profile getApplicationConfigService().addProperty(configClass.getModule(), "url/".concat(endPoint), serviceUrl, profile, true); // Generating the new configuration class if not exists // If provided class already exists, update it ClassOrInterfaceTypeDetailsBuilder cidBuilder = null; if (!isNewConfigClass) { // Obtain builder from the existing class cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(configClassDetails); // Check if already have @RooWsClients annotation AnnotationMetadataBuilder wsClientsAnnotation = cidBuilder.getDeclaredTypeAnnotation(RooJavaType.ROO_WS_CLIENTS); if (wsClientsAnnotation != null) { // Update the existing one AnnotationAttributeValue<?> existingEndPoints = wsClientsAnnotation.build().getAttribute("endpoints"); List<?> values = (List<?>) existingEndPoints.getValue(); if (values != null) { // Check if the provided endpoint exists yet in this config class Iterator<?> it = values.iterator(); boolean alreadyManaged = false; while (it.hasNext()) { NestedAnnotationAttributeValue existingEndPoint = (NestedAnnotationAttributeValue) it.next(); String existingEndpointName = (String) existingEndPoint.getValue().getAttribute("endpoint").getValue(); if (existingEndpointName.equals(endPoint)) { alreadyManaged = true; } } // If endpoint already exists, show an error indicating that this endpoint is already managed if (alreadyManaged) { LOGGER.log(Level.INFO, "ERROR: The provided endpoint is already defined in the provided configuration class. " + "Specify some different configuration class."); return; } else { // Update existing annotation with the new endPoint Iterator<?> iterator = values.iterator(); List<AnnotationAttributeValue<?>> endpoints = new ArrayList<AnnotationAttributeValue<?>>(); while (iterator.hasNext()) { NestedAnnotationAttributeValue existingEndPoint = (NestedAnnotationAttributeValue) iterator.next(); String existingEndpointName = (String) existingEndPoint.getValue().getAttribute("endpoint").getValue(); String existingEndpointNameSpace = (String) existingEndPoint.getValue().getAttribute("targetNamespace").getValue(); EnumDetails existingType = (EnumDetails) existingEndPoint.getValue().getAttribute("binding").getValue(); // Create @RooWsClient annotation NestedAnnotationAttributeValue existingEndpoint = new NestedAnnotationAttributeValue(new JavaSymbolName("value"), getWsClientAnnotation(existingEndpointName, existingEndpointNameSpace, existingType).build()); endpoints.add(existingEndpoint); } // Create @RooWsClient annotation NestedAnnotationAttributeValue newEndpoint = new NestedAnnotationAttributeValue(new JavaSymbolName("value"), getWsClientAnnotation(endPoint, targetNameSpace, bindingType).build()); endpoints.add(newEndpoint); ArrayAttributeValue<AnnotationAttributeValue<?>> newEndpoints = new ArrayAttributeValue<AnnotationAttributeValue<?>>( new JavaSymbolName("endpoints"), endpoints); wsClientsAnnotation.addAttribute(newEndpoints); } } } else { // If not exists, add it with the new elements wsClientsAnnotation = new AnnotationMetadataBuilder(new JavaType(RooWsClients.class)); // Create @RooWsClient annotation List<AnnotationAttributeValue<?>> endpoints = new ArrayList<AnnotationAttributeValue<?>>(); NestedAnnotationAttributeValue newEndpoint = new NestedAnnotationAttributeValue(new JavaSymbolName("value"), getWsClientAnnotation( endPoint, targetNameSpace, bindingType).build()); endpoints.add(newEndpoint); ArrayAttributeValue<AnnotationAttributeValue<?>> newEndpoints = new ArrayAttributeValue<AnnotationAttributeValue<?>>(new JavaSymbolName("endpoints"), endpoints); wsClientsAnnotation.addAttribute(newEndpoints); if (StringUtils.isNotEmpty(profile)) { wsClientsAnnotation.addStringAttribute("profile", profile); } // Include new @RooWsClients annotation cidBuilder.addAnnotation(wsClientsAnnotation); } } else { // Create new configuration class final String configClassIdentifier = getPathResolver().getCanonicalPath(configClass.getModule(), Path.SRC_MAIN_JAVA, configClass); final String mid = PhysicalTypeIdentifier.createIdentifier(configClass, getPathResolver().getPath(configClassIdentifier)); cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(mid, Modifier.PUBLIC, configClass, PhysicalTypeCategory.CLASS); // Create new @RooWsClients annotation AnnotationMetadataBuilder wsClientsAnnotation = new AnnotationMetadataBuilder(new JavaType(RooWsClients.class)); // Create @RooWsClient annotation List<AnnotationAttributeValue<?>> endpoints = new ArrayList<AnnotationAttributeValue<?>>(); NestedAnnotationAttributeValue newEndpoint = new NestedAnnotationAttributeValue(new JavaSymbolName("value"), getWsClientAnnotation( endPoint, targetNameSpace, bindingType).build()); endpoints.add(newEndpoint); ArrayAttributeValue<AnnotationAttributeValue<?>> newEndpoints = new ArrayAttributeValue<AnnotationAttributeValue<?>>(new JavaSymbolName("endpoints"), endpoints); wsClientsAnnotation.addAttribute(newEndpoints); if (StringUtils.isNotEmpty(profile)) { wsClientsAnnotation.addStringAttribute("profile", profile); } // Include new @RooWsClients annotation cidBuilder.addAnnotation(wsClientsAnnotation); } getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilder.build()); // Compile project to be able to generate necessary resources. // Is necessary to create new thread and wat for it. Thread generateSourcesThread = new Thread() { public void run() { try { Thread.sleep(1000); final StringBuilder sb = new StringBuilder(); sb.append(LINE_SEPARATOR); sb.append(LINE_SEPARATOR); sb.append("##########################################################").append( LINE_SEPARATOR); sb.append("##########################################################").append( LINE_SEPARATOR); sb.append("################# Generating client sources ##############").append( LINE_SEPARATOR); sb.append("##########################################################").append( LINE_SEPARATOR); sb.append("##########################################################").append( LINE_SEPARATOR); sb.append("#").append(LINE_SEPARATOR); sb.append("# Please wait...").append(LINE_SEPARATOR); sb.append("# Don't execute any command until this operation finishes.").append( LINE_SEPARATOR); sb.append("#").append(LINE_SEPARATOR); sb.append(LINE_SEPARATOR); sb.append(LINE_SEPARATOR); LOGGER.log(Level.INFO, sb.toString()); // Changing focus to the module where the .wsdl file is located getProjectOperations().setModule(wsdlModule); // executing mvn generate-sources command getMavenOperations().executeMvnCommand("generate-sources"); } catch (InterruptedException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }; generateSourcesThread.start(); } @Override public void addSEI(JavaType service, JavaType sei, JavaType endpointClass, JavaType configClass, String profile, boolean force) { Validate.notNull(service, "ERROR: Provide a valid service"); Validate.notNull(sei, "ERROR: Provide a valid sei"); // Check if provided service exists ClassOrInterfaceTypeDetails serviceTypeDetails = getTypeLocationService().getTypeDetails(service); Validate.notNull(serviceTypeDetails, "ERROR: Provide an existing service"); // Check if provided service is annotated with @RooService AnnotationMetadata serviceAnnotation = serviceTypeDetails.getAnnotation(RooJavaType.ROO_SERVICE); Validate .notNull(serviceAnnotation, "ERROR: Provide a valid service annotated with @RooService"); // Check if provided service has a related entity AnnotationAttributeValue<JavaType> entityAttr = serviceAnnotation.getAttribute("entity"); Validate.notNull(entityAttr, "ERROR: The provided service is annotated with @RooService but doesn't " + "contains the 'entity' attribute"); JavaType relatedEntity = entityAttr.getValue(); Validate.notNull(relatedEntity, "ERROR: The provided service is annotated with @RooService but doesn't " + "contains a valid entity in the 'entity' attribute"); // Check if provided SEI is located in an application module if (!isLocatedInApplicationModule(sei) && !force) { LOGGER.log(Level.INFO, "ERROR: The provided SEI is not located in an application module."); return; } // Check if the configClass is located in an application module if (configClass != null && !isLocatedInApplicationModule(configClass) && !force) { LOGGER.log(Level.INFO, "ERROR: The provided config class is not located in an application module."); return; } // If developer has not specify any EndPoint class is necessary to generate // new one inside the provided SEI module using the provided SEI name and 'Endpoint' suffix. if (endpointClass == null) { endpointClass = new JavaType(String.format("%sEndpoint", sei.getFullyQualifiedTypeName()), sei.getModule()); } // If developer has not specify any configuration class is necessary to generate a // new one inside the provided SEI module using the provided SEI name and 'Configuration' suffix if (configClass == null) { configClass = new JavaType(String.format("%sConfiguration", sei.getFullyQualifiedTypeName()), sei.getModule()); } // Check if provided configClass exists or should be generated boolean isNewConfigClass = false; ClassOrInterfaceTypeDetails configClassDetails = getTypeLocationService().getTypeDetails(configClass); if (configClassDetails == null) { isNewConfigClass = true; } // If exists, is necessary to check if is a configuration class and if it has some specific profile. // If it have it, it should match with the provided one the provided one if (!isNewConfigClass) { MemberDetails configClassMemberDetails = getMemberDetailsScanner().getMemberDetails(getClass().getName(), configClassDetails); AnnotationMetadata configurationAnnotation = configClassMemberDetails.getAnnotation(SpringJavaType.CONFIGURATION); if (configurationAnnotation == null) { LOGGER .log( Level.INFO, "ERROR: The provided class is not annotated with @Configuration so is not possible to include Web Service client configuration on it." + "Specify other configuration class that contains @Configuration annotation or specify a not existing class to generate it."); return; } if (StringUtils.isNotEmpty(profile)) { AnnotationMetadata profileAnnotation = configClassMemberDetails.getAnnotation(SpringJavaType.PROFILE); if (profileAnnotation != null) { String profiles = (String) profileAnnotation.getAttribute("value").getValue(); String[] definedProfiles = profiles.split(","); boolean profileExists = false; for (String definedProfile : definedProfiles) { if (definedProfile.equals(profile)) { profileExists = true; } } if (!profileExists) { LOGGER.log(Level.INFO, "ERROR: The provided configuration class doesn't work in the provided profile. " + "Use a different configuration class or use a different profile."); return; } } } } // Check if some the provided classes that should be generated already exists if (getTypeLocationService().getTypeDetails(sei) != null) { LOGGER.log(Level.INFO, "ERROR: The provided SEI already exists. Specify a different one using" + " --sei parameter."); return; } if (getTypeLocationService().getTypeDetails(endpointClass) != null) { LOGGER.log(Level.INFO, "ERROR: The provided Endpoint class already exists. Specify a different one using" + " --class parameter."); return; } // Include necessary dependencies includeDependenciesAndPluginsForSei(sei.getModule()); // Include the necessary properties using the provided profile getApplicationConfigService().addProperty(sei.getModule(), "cxf.path", "/services", profile, true); getApplicationConfigService().addProperty(sei.getModule(), "cxf.servlet.load-on-startup", "-1", profile, true); // Generate the new SEI final String seiIdentifier = getPathResolver().getCanonicalPath(sei.getModule(), Path.SRC_MAIN_JAVA, sei); final String midSEI = PhysicalTypeIdentifier.createIdentifier(sei, getPathResolver().getPath(seiIdentifier)); ClassOrInterfaceTypeDetailsBuilder cidBuilderSEI = new ClassOrInterfaceTypeDetailsBuilder(midSEI, Modifier.PUBLIC, sei, PhysicalTypeCategory.INTERFACE); // Create new @RooWsEndpoint annotation AnnotationMetadataBuilder seiAnnotation = new AnnotationMetadataBuilder(new JavaType(RooSei.class)); // Including service parameter to @RooSei annotation seiAnnotation.addClassAttribute("service", service); // Include new @RooSei annotation cidBuilderSEI.addAnnotation(seiAnnotation); // Write SEI class on disk getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilderSEI.build()); // Generate the new Endpoint final String endpointIdentifier = getPathResolver().getCanonicalPath(endpointClass.getModule(), Path.SRC_MAIN_JAVA, endpointClass); final String midEndpoint = PhysicalTypeIdentifier.createIdentifier(endpointClass, getPathResolver().getPath(endpointIdentifier)); ClassOrInterfaceTypeDetailsBuilder cidBuilderEndpoint = new ClassOrInterfaceTypeDetailsBuilder(midEndpoint, Modifier.PUBLIC, endpointClass, PhysicalTypeCategory.CLASS); // Create new @RooSeiImpl annotation AnnotationMetadataBuilder endpointAnnotation = new AnnotationMetadataBuilder(new JavaType(RooSeiImpl.class)); // Include sei parameter to @RooSeiImpl annotation endpointAnnotation.addClassAttribute("sei", sei); // Include new @RooSeiImpl annotation cidBuilderEndpoint.addAnnotation(endpointAnnotation); // Include implements cidBuilderEndpoint.addImplementsType(sei); // Write endpoint class on disk getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilderEndpoint.build()); // If configuration class exists, check if is already annotated and update it. // If not exists, create a new one ClassOrInterfaceTypeDetailsBuilder cidBuilderConfig = null; if (!isNewConfigClass) { // Obtain builder from the existing class cidBuilderConfig = new ClassOrInterfaceTypeDetailsBuilder(configClassDetails); // Check if already have @RooWsEndpoints annotation AnnotationMetadataBuilder wsEndpointsAnnotation = cidBuilderConfig.getDeclaredTypeAnnotation(RooJavaType.ROO_WS_ENDPOINTS); if (wsEndpointsAnnotation != null) { // Update the existing one AnnotationAttributeValue<?> existingEndPoints = wsEndpointsAnnotation.build().getAttribute("endpoints"); List<?> values = (List<?>) existingEndPoints.getValue(); if (values != null) { // Check if the provided endpoint exists yet in this config class Iterator<?> it = values.iterator(); boolean alreadyManaged = false; while (it.hasNext()) { ClassAttributeValue existingEndPointAttr = (ClassAttributeValue) it.next(); JavaType existingEndPoint = existingEndPointAttr.getValue(); if (existingEndPoint.getFullyQualifiedTypeName().equals( endpointClass.getFullyQualifiedTypeName())) { alreadyManaged = true; } } // If endpoint already exists, show an error indicating that this endpoint is already managed if (alreadyManaged) { LOGGER.log(Level.INFO, "ERROR: The provided endpoint is already defined in the provided configuration class. " + "Specify some different configuration class."); return; } else { // Update existing annotation with the new endPoint Iterator<?> iterator = values.iterator(); List<AnnotationAttributeValue<?>> endpoints = new ArrayList<AnnotationAttributeValue<?>>(); while (iterator.hasNext()) { ClassAttributeValue existingEndPoint = (ClassAttributeValue) iterator.next(); endpoints.add(existingEndPoint); } // Create @RooWsEndpoints annotation ClassAttributeValue newEndpoint = new ClassAttributeValue(new JavaSymbolName("value"), endpointClass); endpoints.add(newEndpoint); ArrayAttributeValue<AnnotationAttributeValue<?>> newEndpoints = new ArrayAttributeValue<AnnotationAttributeValue<?>>( new JavaSymbolName("endpoints"), endpoints); wsEndpointsAnnotation.addAttribute(newEndpoints); } } } else { // If not exists, add it with the new elements wsEndpointsAnnotation = new AnnotationMetadataBuilder(new JavaType(RooWsEndpoints.class)); // Generate new list of endpoints List<AnnotationAttributeValue<?>> endpoints = new ArrayList<AnnotationAttributeValue<?>>(); ClassAttributeValue newEndpoint = new ClassAttributeValue(new JavaSymbolName("value"), endpointClass); endpoints.add(newEndpoint); ArrayAttributeValue<AnnotationAttributeValue<?>> newEndpoints = new ArrayAttributeValue<AnnotationAttributeValue<?>>(new JavaSymbolName("endpoints"), endpoints); wsEndpointsAnnotation.addAttribute(newEndpoints); // Check if is necessary to include profile attribute if (StringUtils.isNotEmpty(profile)) { wsEndpointsAnnotation.addStringAttribute("profile", profile); } // Include new @RooWsEndpoints annotation cidBuilderConfig.addAnnotation(wsEndpointsAnnotation); } } else { // Create the specified configuration class and annotate it with necessary information final String configClassIdentifier = getPathResolver().getCanonicalPath(configClass.getModule(), Path.SRC_MAIN_JAVA, configClass); final String mid = PhysicalTypeIdentifier.createIdentifier(configClass, getPathResolver().getPath(configClassIdentifier)); cidBuilderConfig = new ClassOrInterfaceTypeDetailsBuilder(mid, Modifier.PUBLIC, configClass, PhysicalTypeCategory.CLASS); // Create new @RooWsEndpoints annotation and include the new endpoint // as endpoints attribute List<AnnotationAttributeValue<?>> endpoints = new ArrayList<AnnotationAttributeValue<?>>(); ClassAttributeValue endPointAttributeValue = new ClassAttributeValue(new JavaSymbolName("value"), endpointClass); endpoints.add(endPointAttributeValue); ArrayAttributeValue<AnnotationAttributeValue<?>> newEndpoints = new ArrayAttributeValue<AnnotationAttributeValue<?>>(new JavaSymbolName("endpoints"), endpoints); AnnotationMetadataBuilder wsEndpointsAnnotation = new AnnotationMetadataBuilder(new JavaType(RooWsEndpoints.class)); wsEndpointsAnnotation.addAttribute(newEndpoints); // Include new @RooWsEndpoints annotation cidBuilderConfig.addAnnotation(wsEndpointsAnnotation); // Include @Profile annotation with the provided profile. This annotation // doesn't exists yet, because we're generating a new @Configuration class if (StringUtils.isNotEmpty(profile)) { wsEndpointsAnnotation.addStringAttribute("profile", profile); } } // Write config class on disk getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilderConfig.build()); // After create the SEI and the Endpoint, is necessary to annotate related entity with // some JAX-B annotations if has not been annotated before /*ClassOrInterfaceTypeDetails entityDetails = getTypeLocationService().getTypeDetails(relatedEntity); if (entityDetails != null) { // Annotate the entity with @RooJaxbEntity. If this entity has a super class or that // super class has another super class, etc. is necessary to annotate it too. annotateClassIfNeeded(entityDetails); // Also, is necessary to annotate @OneToMany, @ManyToOne and @ManyToMany fields detected in // this class and in the super classes. annotateRelatedFieldsIfNeeded(entityDetails); }*/ // Provisional changes to annotate all entities Set<ClassOrInterfaceTypeDetails> allEntities = getTypeLocationService().findClassesOrInterfaceDetailsWithAnnotation( RooJavaType.ROO_JPA_ENTITY); for (ClassOrInterfaceTypeDetails entity : allEntities) { // Annotate the entity with @RooJaxbEntity. If this entity has a super class or that // super class has another super class, etc. is necessary to annotate it too. annotateClassIfNeeded(entity); // Also, is necessary to annotate @OneToMany, @ManyToOne and @ManyToMany fields detected in // this class and in the super classes. annotateRelatedFieldsIfNeeded(entity); } } /** * This method annotates the provided class with @RooJaxbEntity. If this class extends * other classes, and that classes annotates other classes, etc. * this method will annotate them. * * @param entityDetails */ private void annotateClassIfNeeded(ClassOrInterfaceTypeDetails entityDetails) { List<JavaType> extendsTypes = entityDetails.getExtendsTypes(); for (JavaType extendsType : extendsTypes) { ClassOrInterfaceTypeDetails extendsTypeDetails = getTypeLocationService().getTypeDetails(extendsType); if (extendsTypeDetails != null && extendsTypeDetails.getAnnotation(RooJavaType.ROO_JPA_ENTITY) != null) { // If annotation has not been included before, add it. if (extendsTypeDetails.getAnnotation(RooJavaType.ROO_JAXB_ENTITY) == null) { ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(extendsTypeDetails); // Include @RooJaxbEntity annotation AnnotationMetadataBuilder jaxbEntityAnnotation = new AnnotationMetadataBuilder(RooJavaType.ROO_JAXB_ENTITY); cidBuilder.addAnnotation(jaxbEntityAnnotation); // Write entity class on disk getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilder.build()); } // Repeat the same process until all super classes // have been annotated if (!extendsTypeDetails.getExtendsTypes().isEmpty()) { annotateClassIfNeeded(extendsTypeDetails); } } } // If annotation has not been included before, add it. if (entityDetails.getAnnotation(RooJavaType.ROO_JAXB_ENTITY) == null) { ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(entityDetails); // Include @RooJaxbEntity annotation AnnotationMetadataBuilder jaxbEntityAnnotation = new AnnotationMetadataBuilder(RooJavaType.ROO_JAXB_ENTITY); cidBuilder.addAnnotation(jaxbEntityAnnotation); // Write entity class on disk getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilder.build()); } } /** * This method annotates the provided class with @RooJaxbEntity. If this class extends * other classes, and that classes annotates other classes, etc. * this method will annotate them. * * @param entityDetails */ private void annotateRelatedFieldsIfNeeded(ClassOrInterfaceTypeDetails entityDetails) { // Getting details of the provided entity MemberDetails memberDetails = getMemberDetailsScanner().getMemberDetails(getClass().getName(), entityDetails); // Getting all its fields for (FieldMetadata entityField : memberDetails.getFields()) { // If is a relation field, should be annotated if (entityField.getAnnotation(JpaJavaType.ONE_TO_ONE) != null || entityField.getAnnotation(JpaJavaType.ONE_TO_MANY) != null || entityField.getAnnotation(JpaJavaType.MANY_TO_ONE) != null || entityField.getAnnotation(JpaJavaType.MANY_TO_MANY) != null) { // Getting details of the annotated field JavaType fieldType = entityField.getFieldType(); if (fieldType.isCommonCollectionType()) { fieldType = fieldType.getBaseType(); } ClassOrInterfaceTypeDetails fieldDetails = getTypeLocationService().getTypeDetails(fieldType); // If is a valid entity if (fieldDetails != null && fieldDetails.getAnnotation(RooJavaType.ROO_JPA_ENTITY) != null) { // Delegates in annotateClassIfNeeded to annotate the related class field annotateClassIfNeeded(fieldDetails); } } } } @Override public Pom getModuleFromWsdlLocation(String wsdlLocation) { // Separate the wsdlLocation and the module String[] wsdlLocationParts = wsdlLocation.split(":"); if (wsdlLocationParts.length > 1) { return getProjectOperations().getPomFromModuleName(wsdlLocationParts[0]); } else { return getProjectOperations().getPomFromModuleName(""); } } @Override public String getWsdlNameWithoutModule(String wsdlLocation) { // Separate the wsdlLocation and the module String[] wsdlLocationParts = wsdlLocation.split(":"); if (wsdlLocationParts.length > 1) { return wsdlLocationParts[1]; } else { return wsdlLocation; } } @Override public String getWsdlAbsolutePathFromWsdlName(String wsdlLocation) { // Getting root path String rootPath = getPathResolver().getRoot(); // Getting module name and wsdl name from the provided wsdlName String wsdlName = getWsdlNameWithoutModule(wsdlLocation); String moduleName = getModuleFromWsdlLocation(wsdlLocation).getModuleName(); return rootPath.concat("/").concat(moduleName).concat("/src/main/resources/").concat(wsdlName); } @Override public List<String> getEndPointsFromWsdlFile(String wsdlPath) { List<String> availableEndPoints = new ArrayList<String>(); // Check if provided wsdl file exists if (getFileManager().exists(wsdlPath)) { // Obtain document final Document document = XmlUtils.readXml(getFileManager().getInputStream(wsdlPath)); // Finding service elements List<Element> services = XmlUtils.findElements("service", document.getDocumentElement()); for (Element service : services) { NodeList ports = service.getChildNodes(); for (int i = 0; i < ports.getLength(); i++) { Element port = (Element) ports.item(1); if (port != null && port.getAttribute("name") != null) { availableEndPoints.add(port.getAttribute("name")); } } } } return availableEndPoints; } @Override public String getTargetNameSpaceFromWsdlFile(String wsdlPath) { // Check if provided wsdl file exists if (getFileManager().exists(wsdlPath)) { // Obtain document final Document document = XmlUtils.readXml(getFileManager().getInputStream(wsdlPath)); // Return targetNamespace return document.getDocumentElement().getAttribute("targetNamespace"); } return null; } @Override public SoapBindingType getBindingTypeFromWsdlFile(String wsdlPath) { // Check if provided wsdl file exists if (getFileManager().exists(wsdlPath)) { // Obtain document final Document document = XmlUtils.readXml(getFileManager().getInputStream(wsdlPath)); // Get soap attribute String soapAttr = document.getDocumentElement().getAttribute("xmlns:soap"); if ("http://schemas.xmlsoap.org/wsdl/soap/".equals(soapAttr)) { return SoapBindingType.SOAP11; } else if ("http://schemas.xmlsoap.org/wsdl/soap12/".equals(soapAttr)) { return SoapBindingType.SOAP12; } else if (soapAttr == null || "".equals(soapAttr)) { // Maybe attribute is called soap12 String soap12Attr = document.getDocumentElement().getAttribute("xmlns:soap12"); if ("http://schemas.xmlsoap.org/wsdl/soap12/".equals(soap12Attr)) { return SoapBindingType.SOAP12; } } } return null; } @Override public String getServiceUrlForEndpointFromWsdlFile(String endPoint, String wsdlPath) { // Check if provided wsdl file exists if (getFileManager().exists(wsdlPath)) { // Obtain document final Document document = XmlUtils.readXml(getFileManager().getInputStream(wsdlPath)); // Finding service elements List<Element> services = XmlUtils.findElements("service", document.getDocumentElement()); for (Element service : services) { NodeList ports = service.getChildNodes(); for (int i = 0; i < ports.getLength(); i++) { Element port = (Element) ports.item(1); // Check if current endPoint has the same name as the provided one if (port != null && port.getAttribute("name") != null && endPoint.equals(port.getAttribute("name"))) { NodeList addresses = port.getChildNodes(); for (int x = 0; x < addresses.getLength(); x++) { if (addresses.item(x) != null && addresses.item(x) instanceof Element) { Element address = (Element) addresses.item(x); return address.getAttribute("location"); } } } } } } return null; } /** * This method provides @RooWsClient annotation with all the necessary attributes * * @param endpoint * @param targetNamespace * @param bindingType * @return */ private AnnotationMetadataBuilder getWsClientAnnotation(final String endpoint, final String targetNamespace, final SoapBindingType bindingType) { final List<AnnotationAttributeValue<?>> wsClientAttributes = new ArrayList<AnnotationAttributeValue<?>>(); wsClientAttributes.add(new StringAttributeValue(new JavaSymbolName("endpoint"), endpoint)); wsClientAttributes.add(new StringAttributeValue(new JavaSymbolName("targetNamespace"), targetNamespace)); wsClientAttributes.add(new EnumAttributeValue(new JavaSymbolName("binding"), new EnumDetails( RooJavaType.ROO_ENUM_SOAP_BINDING_TYPE, new JavaSymbolName(bindingType.name())))); return new AnnotationMetadataBuilder(RooJavaType.ROO_WS_CLIENT, wsClientAttributes); } /** * This method provides @RooWsClient annotation with all the necessary attributes * * @param endpoint * @param targetNamespace * @param bindingType * @return */ private AnnotationMetadataBuilder getWsClientAnnotation(final String endpoint, final String targetNamespace, final EnumDetails bindingType) { final List<AnnotationAttributeValue<?>> wsClientAttributes = new ArrayList<AnnotationAttributeValue<?>>(); wsClientAttributes.add(new StringAttributeValue(new JavaSymbolName("endpoint"), endpoint)); wsClientAttributes.add(new StringAttributeValue(new JavaSymbolName("targetNamespace"), targetNamespace)); wsClientAttributes.add(new EnumAttributeValue(new JavaSymbolName("binding"), bindingType)); return new AnnotationMetadataBuilder(RooJavaType.ROO_WS_CLIENT, wsClientAttributes); } /** * This method includes the TracEE and CXF dependencies and includes the CXF * CodeGen Plugin with the necessary configuration for the new WsClient. * * @param wsdlName * the wsdl name * @param wsdlModuleName * the module where the wsdl is located */ private void includeDependenciesAndPluginsForWsClient(String wsdlName, String wsdlModuleName) { // Include CXF property if not exists getProjectOperations().addProperty("", CXF_PROPERTY); getProjectOperations().addDependency(wsdlModuleName, CXF_RT_FRONTEND_JAXWS_DEPENDENCY); getProjectOperations().addDependency(wsdlModuleName, CXF_RT_TRANSPORTS_HTTP_DEPENDENCY); // Include TracEE dependencies if not exists getProjectOperations().addProperty("", TRACEE_PROPERTY); getProjectOperations().addDependency(wsdlModuleName, TRACEE_CXF_DEPENDENCY); // Include CXF plugin if not exists final Element configuration = XmlUtils.getConfiguration(getClass()); final List<Element> plugins = XmlUtils.findElements("/configuration/plugins/plugin", configuration); Plugin cxfPlugin = null; for (final Element pluginElement : plugins) { cxfPlugin = new Plugin(pluginElement); getProjectOperations().addBuildPlugin(wsdlModuleName, cxfPlugin); break; } // Update cxf plugin with the new wsdl Map<String, String> wsdlLocationProperties = new HashMap<String, String>(); wsdlLocationProperties.put("wsdl", "${project.basedir}/src/main/resources/" + wsdlName); wsdlLocationProperties.put("wsdlLocation", "classpath:" + wsdlName); getProjectOperations().addElementToPluginExecution(wsdlModuleName, cxfPlugin, "generate-sources", "wsdlOptions", "wsdlOption", wsdlLocationProperties); } /** * This method includes the TracEE and CXF dependencies. Also, include the CXF starter * * @param moduleName * the module where the dependencies will be included */ private void includeDependenciesAndPluginsForSei(String moduleName) { // Include CXF property if not exists getProjectOperations().addProperty("", CXF_PROPERTY); getProjectOperations().addDependency(moduleName, CXF_STARTER_DEPENDENCY); // Include TracEE dependencies if not exists getProjectOperations().addProperty("", TRACEE_PROPERTY); getProjectOperations().addDependency(moduleName, TRACEE_JAXWS_DEPENDENCY); getProjectOperations().addDependency(moduleName, TRACEE_CXF_DEPENDENCY); } /** * This method check if the provided element is located in an application * module or not * * @param type */ private boolean isLocatedInApplicationModule(JavaType type) { if (type == null) { return false; } else if ("".equals(type.getModule())) { return true; } else { String moduleName = type.getModule(); // Getting all application modules Collection<Pom> modules = getTypeLocationService().getModules(ModuleFeatureName.APPLICATION); for (Pom pom : modules) { if (pom.getModuleName().equals(moduleName)) { return true; } } } return false; } // Obtaining OSGi services using ServiceInstaceManager utility public ProjectOperations getProjectOperations() { return serviceInstaceManager.getServiceInstance(this, ProjectOperations.class); } public TypeLocationService getTypeLocationService() { return serviceInstaceManager.getServiceInstance(this, TypeLocationService.class); } public ApplicationConfigService getApplicationConfigService() { return serviceInstaceManager.getServiceInstance(this, ApplicationConfigService.class); } public TypeManagementService getTypeManagementService() { return serviceInstaceManager.getServiceInstance(this, TypeManagementService.class); } public PathResolver getPathResolver() { return serviceInstaceManager.getServiceInstance(this, PathResolver.class); } public MemberDetailsScanner getMemberDetailsScanner() { return serviceInstaceManager.getServiceInstance(this, MemberDetailsScanner.class); } public FileManager getFileManager() { return serviceInstaceManager.getServiceInstance(this, FileManager.class); } public MavenOperations getMavenOperations() { return serviceInstaceManager.getServiceInstance(this, MavenOperations.class); } }