/*
* gvNIX is an open source tool for rapid application development (RAD).
* Copyright (C) 2010 Generalitat Valenciana
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gvnix.service.roo.addon.addon.ws.export;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
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.Reference;
import org.apache.felix.scr.annotations.Service;
import org.gvnix.service.roo.addon.addon.JavaParserService;
import org.gvnix.service.roo.addon.addon.security.SecurityService;
import org.gvnix.service.roo.addon.addon.util.WsdlParserUtils;
import org.gvnix.service.roo.addon.addon.ws.WSCompilationUnit;
import org.gvnix.service.roo.addon.addon.ws.WSConfigService;
import org.gvnix.service.roo.addon.annotations.GvNIXWebService;
import org.gvnix.service.roo.addon.annotations.GvNIXXmlElement;
import org.springframework.roo.classpath.PhysicalTypeCategory;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.details.ConstructorMetadata;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.MethodMetadata;
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.BooleanAttributeValue;
import org.springframework.roo.classpath.details.annotations.EnumAttributeValue;
import org.springframework.roo.classpath.details.annotations.StringAttributeValue;
import org.springframework.roo.file.monitor.NotifiableFileMonitorService;
import org.springframework.roo.file.monitor.event.FileDetails;
import org.springframework.roo.model.EnumDetails;
import org.springframework.roo.model.JavaPackage;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.ProjectOperations;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import com.github.antlrjavaparser.JavaParser;
import com.github.antlrjavaparser.ParseException;
import com.github.antlrjavaparser.api.CompilationUnit;
import com.github.antlrjavaparser.api.PackageDeclaration;
import com.github.antlrjavaparser.api.body.BodyDeclaration;
import com.github.antlrjavaparser.api.body.ClassOrInterfaceDeclaration;
import com.github.antlrjavaparser.api.body.ConstructorDeclaration;
import com.github.antlrjavaparser.api.body.EnumConstantDeclaration;
import com.github.antlrjavaparser.api.body.EnumDeclaration;
import com.github.antlrjavaparser.api.body.FieldDeclaration;
import com.github.antlrjavaparser.api.body.MethodDeclaration;
import com.github.antlrjavaparser.api.body.TypeDeclaration;
import com.github.antlrjavaparser.api.expr.AnnotationExpr;
import com.github.antlrjavaparser.api.expr.FieldAccessExpr;
import com.github.antlrjavaparser.api.expr.MarkerAnnotationExpr;
import com.github.antlrjavaparser.api.expr.MemberValuePair;
import com.github.antlrjavaparser.api.expr.NormalAnnotationExpr;
import com.github.antlrjavaparser.api.expr.SingleMemberAnnotationExpr;
import com.github.antlrjavaparser.api.expr.StringLiteralExpr;
import com.github.antlrjavaparser.api.type.ClassOrInterfaceType;
/**
* @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a
* href="http://www.dgti.gva.es">General Directorate for Information
* Technologies (DGTI)</a>
*/
@Component
@Service
public class WSExportWsdlConfigServiceImpl implements WSExportWsdlConfigService {
/*
* Variables to store web files of web service generated by maven wsdl2java
* plugin. TODO THIS IS NO THREAD-SAFE. EXTRACT IT to a process class and
* identify in every WsExportWsdlListener call what process refers the file
*/
private List<File> xmlElements = new ArrayList<File>();
private List<File> webFaults = new ArrayList<File>();
private List<File> webServices = new ArrayList<File>();
private List<File> webServiceInterfaces = new ArrayList<File>();
private File schemaPackage = new File("");
static final String PACKAGE_INFO_FILE = "package-info.java";
static final String webService = "javax.jws.WebService";
static final String webServiceInterface = "WebService";
static final String soapBinding = "SOAPBinding";
static final String xmlRootElement = "XmlRootElement";
static final String xmlAccessorType = "XmlAccessorType";
static final String xmlType = "XmlType";
static final String xmlEnum = "XmlEnum";
static final String webFault = "WebFault";
@Reference
private WSConfigService wSConfigService;
@Reference
private ProjectOperations projectOperations;
@Reference
private NotifiableFileMonitorService fileMonitorService;
@Reference
private SecurityService securityService;
@Reference
private WsExportWsdl wsExportWsdl;
@Reference
private FileManager fileManager;
@Reference
private JavaParserService javaParserService;
protected static Logger logger = Logger
.getLogger(WSExportWsdlConfigService.class.getName());
/**
* {@inheritDoc}
*/
public void generateJavaFromWsdl(String wsdlLocation) {
// Check if WSDL is RPC enconded and copy file to project
Document wsdlDocument = checkWSDLFile(wsdlLocation);
// Configure plugin cxf to generate java code using WSDL
wSConfigService.addWsdlLocation(wsdlLocation, wsdlDocument);
// Reset to generate file list
resetGeneratedFilesList();
try {
// Run maven generate-sources command
wSConfigService.mvn(WSConfigService.GENERATE_SOURCES,
WSConfigService.GENERATE_SOURCES_INFO);
}
catch (IOException e) {
throw new IllegalStateException(
"There is an error generating java sources with '"
+ wsdlLocation + "'.\n" + e.getMessage());
}
// Remove plugin execution
wSConfigService.disableWsdlLocation();
}
/**
* Get XML document representation from WSDL if valid.
* <p>
* Check WSDL is not RPC Encoded and has only one compatible port.
* </p>
*
* @param url from WSDL file to export
* @return XML document representation of WSDL
*/
protected Document checkWSDLFile(String url) {
// Check URL connection and WSDL format
Element root = securityService.getWsdl(url).getDocumentElement();
Validate.isTrue(!WsdlParserUtils.isRpcEncoded(root), "This Wsdl '"
+ url + "' is RPC Encoded and is not supported by the Add-on.");
// Check if is compatible port defined with SOAP12 or SOAP11.
WsdlParserUtils.checkCompatiblePort(root);
return root.getOwnerDocument();
}
/**
* Reset files values.
*/
protected void resetGeneratedFilesList() {
// Reset File List
xmlElements = new ArrayList<File>();
webFaults = new ArrayList<File>();
webServices = new ArrayList<File>();
webServiceInterfaces = new ArrayList<File>();
schemaPackage = new File("");
}
/**
* {@inheritDoc}
* <p>
* Monitoring file creation only.
* </p>
*/
public void monitorFolder(String folder) {
// Get path to monitoring folder
String path = projectOperations.getPathResolver().getIdentifier(
LogicalPath.getInstance(Path.ROOT, ""), folder);
resetGeneratedFilesList();
SortedSet<FileDetails> files = fileMonitorService
.findMatchingAntPath(path + "/**");
for (FileDetails file : files) {
parseFile(file.getFile());
}
}
/**
* Parse target file for src generation when is valid.
* <p>
* Consider only when:
* </p>
* <ul>
* <li>File is not a directory and included on generated sources dir</li>
* </ul>
* <p>
* Include file for generation when is a package info file (special
* generated java file). Or check file first java type first valid
* annotation type and name if type is a class, interface or enumeration:
* </p>
* <p>
* Only files with valid annotations will be included
* {@link WSExportWsdlImpl#includeFileValidAnnot(File, AnnotationExpr, TypeDeclaration)}
* </p>
*
* @param file File
**/
protected void parseFile(File file) {
// Is not a directory and is included on generated sources dir
if (file.getAbsolutePath().contains(wsExportWsdl.getGenSourcesDir())
&& !file.isDirectory()) {
// When is a package info file (special generated java file)
if (file.getName().contentEquals(PACKAGE_INFO_FILE)) {
setSchemaPackageInfoFile(file);
return;
}
try {
// Get java types from java file
List<TypeDeclaration> types = JavaParser.parse(file).getTypes();
if (types != null) {
// Get fist java type
TypeDeclaration type = types.get(0);
// If java type is a class, interface or enumeration
if ((type instanceof ClassOrInterfaceDeclaration)
|| (type instanceof EnumDeclaration)) {
logger.fine(file.getAbsolutePath());
// First valid annot type and name include generate
for (AnnotationExpr annot : type.getAnnotations()) {
if (includeFileValidAnnot(file, annot, type)) {
break;
}
}
}
}
}
catch (ParseException e) {
throw new IllegalStateException(
"Generated web service java file has errors:\n"
+ e.getMessage());
}
catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException(
"Generated web service java file has errors:\n"
+ e.getMessage());
}
}
}
/**
* Updates package info file location. <b>For {@link WSExportWsdlImpl} uses
* only</b>
*
* @param schemaPackageInfoFile File absolute path.
*/
private void setSchemaPackageInfoFile(File schemaPackageInfoFile) {
this.schemaPackage = schemaPackageInfoFile;
}
/**
* When annotation has a valid class and name, include file for generation.
* <ul>
* <li>Xml root element or xml accessor type: include file for xml element
* generation</li>
* <li>Web fault: include file for web fault generation</li>
* <li>Web service: include file for web service generation
* <li>Web service interface: include file for web service interface
* generation</li>
* <li>Xml enum: include file for xml element generation</li>
* </ul>
* <p>
* Only files with valid annotations names will be included
* {@link WSExportWsdlImpl#includeFileValidAnnotName(File, TypeDeclaration, String)}
* </p>
*
* @param file Generated file
* @param annot File type annotation
* @param type File type
* @return Is valid annotation class and name included for generation ?
*/
private boolean includeFileValidAnnot(File file, AnnotationExpr annot,
TypeDeclaration type) {
if (annot instanceof NormalAnnotationExpr) {
return includeFileValidAnnotName(file, type,
((NormalAnnotationExpr) annot).getName().toString());
}
else if (annot instanceof MarkerAnnotationExpr) {
return includeFileValidAnnotName(file, type,
((MarkerAnnotationExpr) annot).getName().toString());
}
else if (annot instanceof SingleMemberAnnotationExpr) {
return includeFileValidAnnotName(file, type,
((SingleMemberAnnotationExpr) annot).getName().toString());
}
return false;
}
/**
* When annotation has a valid name, include file for generation.
* <ul>
* <li>Xml root element or xml accessor type: include file for xml element
* generation</li>
* <li>Web fault: include file for web fault generation</li>
* <li>Web service: include file for web service generation</li>
* <li>Web service interface: include file for web service interface
* generation</li>
* <li>Xml enum: include file for xml element generation</li>
* </ul>
*
* @param file Generated file
* @param annot File type annotation
* @param name Annotation name
* @return Is valid annotation name included for generation ?
*/
private boolean includeFileValidAnnotName(File file, TypeDeclaration type,
String name) {
if (name.equals(xmlRootElement) || name.equals(xmlAccessorType)) {
addFileToUpdateAnnotation(file, GvNIXAnnotationType.XML_ELEMENT);
return true;
}
else if (name.equals(webFault)) {
addFileToUpdateAnnotation(file, GvNIXAnnotationType.WEB_FAULT);
return true;
}
else if (name.equals(webService)) {
addFileToUpdateAnnotation(file, GvNIXAnnotationType.WEB_SERVICE);
return true;
}
else if (name.equals(webServiceInterface)) {
addFileToUpdateAnnotation(file,
GvNIXAnnotationType.WEB_SERVICE_INTERFACE);
return true;
}
else if (name.equals(xmlEnum)) {
addFileToUpdateAnnotation(file, GvNIXAnnotationType.XML_ELEMENT);
return true;
}
return false;
}
/**
* Updates list of files generated to update with '@gvNIX' annotations.
* <b>For {@link WSExportWsdlImpl} uses only</b>
*
* @param file scanned to add to list.
* @param gvNIXAnnotationType to select the list where add the file.
*/
private void addFileToUpdateAnnotation(File file,
GvNIXAnnotationType gvNIXAnnotationType) {
switch (gvNIXAnnotationType) {
case XML_ELEMENT:
xmlElements.add(file);
break;
case WEB_FAULT:
webFaults.add(file);
break;
case WEB_SERVICE:
webServices.add(file);
break;
case WEB_SERVICE_INTERFACE:
webServiceInterfaces.add(file);
break;
}
}
/**
* {@inheritDoc}
*/
public List<JavaType> createGvNixClasses() {
// Create java classes with @GvNIXXmlElement annotation
createGvNixXmlElementsClasses();
// Create java classes with @GvNIXWebFault annotation
createGvNixWebFaultClasses();
// Create java classes with @GvNIXWebService annotation
return createGvNixWebServiceClasses();
}
/**
* Create in 'src/main/java' gvNIX xml elements from wsdl2java classes list.
* <p>
* The wsdl2java classes list are registered by {@link WSExportWsdlImpl}
* </p>
*/
protected void createGvNixXmlElementsClasses() {
for (File file : xmlElements) {
// File directory
String path = file.getAbsolutePath();
path = path.substring(0, path.lastIndexOf(File.separator) + 1);
try {
// Get first type from java file
CompilationUnit compUnit = JavaParser.parse(file);
List<TypeDeclaration> types = compUnit.getTypes();
if (types != null) {
createGvNixXmlElementClass(types.get(0), compUnit, path);
}
}
catch (ParseException e) {
throw new IllegalStateException(
"Generated Xml Element service java file '"
+ file.getAbsolutePath() + "' has errors:\n"
+ e.getMessage());
}
catch (IOException e) {
throw new IllegalStateException(
"Generated Xml Element service java file '"
+ file.getAbsolutePath() + "' has errors:\n"
+ e.getMessage());
}
}
// Copy 'package-info.java' from generated to sources folder
createPackageInfoClass();
}
/**
* <p>
* Creates web service fail java files in 'src/main/java' from result of
* wsdl2java plugin. In addition, adds @GvNIXWebService annotation.
* </p>
* <p>
* This files will be registered by {@link WSExportWsdlImpl}
* </p>
* TODO to be removed from interface. This method need a sequence of
* operations to be useful.
*/
protected void createGvNixWebFaultClasses() {
List<AnnotationMetadata> gvNixAnnotationList;
// GvNIXWebFault annotation.
AnnotationMetadata gvNIXWebFaultAnnotation;
for (File webFaultFile : webFaults) {
// Parse Java file.
CompilationUnit compilationUnit;
PackageDeclaration packageDeclaration;
JavaType javaType;
String declaredByMetadataId;
// CompilationUnitServices to create the class in fileSystem.
WSCompilationUnit compilationUnitServices;
gvNixAnnotationList = new ArrayList<AnnotationMetadata>();
try {
compilationUnit = JavaParser.parse(webFaultFile);
packageDeclaration = compilationUnit.getPackage();
String packageName = packageDeclaration.getName().toString();
// Get the first class or interface Java type
List<TypeDeclaration> types = compilationUnit.getTypes();
if (types != null) {
TypeDeclaration type = types.get(0);
ClassOrInterfaceDeclaration classOrInterfaceDeclaration;
if (type instanceof ClassOrInterfaceDeclaration) {
javaType = new JavaType(packageName.concat(".").concat(
type.getName()));
classOrInterfaceDeclaration = (ClassOrInterfaceDeclaration) type;
declaredByMetadataId = PhysicalTypeIdentifier
.createIdentifier(javaType, LogicalPath
.getInstance(Path.SRC_MAIN_JAVA, ""));
// Retrieve correct values.
// Get field declarations.
List<FieldMetadata> fieldMetadataList = new ArrayList<FieldMetadata>();
List<ConstructorMetadata> constructorMetadataList = new ArrayList<ConstructorMetadata>();
List<MethodMetadata> methodMetadataList = new ArrayList<MethodMetadata>();
// Extended classes.
List<JavaType> extendedClassesList = new ArrayList<JavaType>();
List<ClassOrInterfaceType> extendsClasses = classOrInterfaceDeclaration
.getExtends();
JavaType extendedJavaType;
for (ClassOrInterfaceType classOrInterfaceType : extendsClasses) {
extendedJavaType = new JavaType(
classOrInterfaceType.getName());
extendedClassesList.add(extendedJavaType);
}
// CompilationUnitServices to create the class.
compilationUnitServices = new WSCompilationUnit(
new JavaPackage(compilationUnit.getPackage()
.getName().toString()), javaType,
compilationUnit.getImports(),
new ArrayList<TypeDeclaration>(),
PhysicalTypeCategory.CLASS);
for (BodyDeclaration bodyDeclaration : classOrInterfaceDeclaration
.getMembers()) {
if (bodyDeclaration instanceof FieldDeclaration) {
wsExportWsdl.loadFaultFieldDeclaration(
declaredByMetadataId,
compilationUnitServices,
fieldMetadataList, bodyDeclaration);
}
else if (bodyDeclaration instanceof ConstructorDeclaration) {
wsExportWsdl.loadFaultConstructorDeclaration(
declaredByMetadataId,
compilationUnitServices,
constructorMetadataList,
bodyDeclaration);
}
else if (bodyDeclaration instanceof MethodDeclaration) {
wsExportWsdl.loadFaultMethodDeclaration(
declaredByMetadataId,
compilationUnitServices,
methodMetadataList,
(MethodDeclaration) bodyDeclaration);
}
}
// GvNIXWebFault Annotation.Get all annotations.
gvNIXWebFaultAnnotation = wsExportWsdl
.getGvNIXWebFaultAnnotation(
classOrInterfaceDeclaration, javaType);
gvNixAnnotationList.add(gvNIXWebFaultAnnotation);
javaParserService.createGvNixWebServiceClass(javaType,
gvNixAnnotationList,
GvNIXAnnotationType.WEB_FAULT,
fieldMetadataList, methodMetadataList,
constructorMetadataList, extendedClassesList,
PhysicalTypeCategory.CLASS, null);
}
}
}
catch (ParseException e) {
throw new IllegalStateException(
"Generated Web Fault service Element java file '"
+ webFaultFile.getAbsolutePath()
+ "' has errors:\n" + e.getMessage());
}
catch (IOException e) {
throw new IllegalStateException(
"Generated Web Fault service Element java file '"
+ webFaultFile.getAbsolutePath()
+ "' has errors:\n" + e.getMessage());
}
}
}
/**
* <p>
* Creates web service java files in 'src/main/java' from result of
* wsdl2java plugin. In addition, adds @GvNIXWebService annotation.
* </p>
* <p>
* This files will be registered by {@link WSExportWsdlImpl}
* </p>
* TODO to be removed from interface. This method need a sequence of
* operations to be useful.
*
* @return implementation class list
*/
protected List<JavaType> createGvNixWebServiceClasses() {
List<AnnotationMetadata> gvNixAnnotationList;
List<JavaType> implementationClasses = new ArrayList<JavaType>();
// GvNIXWebService annotation.
AnnotationMetadata gvNIXWebServiceAnnotation;
for (File webServiceFile : webServices) {
// Parse Java file.
CompilationUnit compilationUnit;
PackageDeclaration packageDeclaration;
JavaType javaType;
String declaredByMetadataId;
// CompilationUnitServices to create the class in fileSystem.
WSCompilationUnit compilationUnitServices;
gvNixAnnotationList = new ArrayList<AnnotationMetadata>();
try {
compilationUnit = JavaParser.parse(webServiceFile);
packageDeclaration = compilationUnit.getPackage();
String packageName = packageDeclaration.getName().toString();
List<TypeDeclaration> types = compilationUnit.getTypes();
if (types == null) {
// nothing to do
return implementationClasses;
}
// Get the first class or interface Java type
TypeDeclaration type = types.get(0);
ClassOrInterfaceDeclaration classOrInterfaceDeclaration;
ClassOrInterfaceDeclaration implementedInterface;
if (type instanceof ClassOrInterfaceDeclaration) {
javaType = new JavaType(packageName.concat(".").concat(
type.getName()));
classOrInterfaceDeclaration = (ClassOrInterfaceDeclaration) type;
declaredByMetadataId = PhysicalTypeIdentifier
.createIdentifier(javaType, LogicalPath
.getInstance(Path.SRC_MAIN_JAVA, ""));
// Retrieve implemented interface.
implementedInterface = getWebServiceInterface(classOrInterfaceDeclaration);
// Retrieve correct values.
// Get field declarations.
List<FieldMetadata> fieldMetadataList = new ArrayList<FieldMetadata>();
List<ConstructorMetadata> constructorMetadataList = new ArrayList<ConstructorMetadata>();
List<MethodMetadata> methodMetadataList = new ArrayList<MethodMetadata>();
// Extended classes.
List<JavaType> extendedClassesList = new ArrayList<JavaType>();
// CompilationUnitServices to create the class.
compilationUnitServices = new WSCompilationUnit(
new JavaPackage(compilationUnit.getPackage()
.getName().toString()), javaType,
compilationUnit.getImports(),
new ArrayList<TypeDeclaration>(),
PhysicalTypeCategory.CLASS);
// GvNIXWebFault Annotation.Get all annotations.
gvNIXWebServiceAnnotation = getGvNIXWebServiceAnnotation(
classOrInterfaceDeclaration, implementedInterface,
javaType);
gvNixAnnotationList.add(gvNIXWebServiceAnnotation);
// Default Web Service Namespace.
AnnotationAttributeValue<?> tarNamespaceAnnAttrVal = gvNIXWebServiceAnnotation
.getAttribute(new JavaSymbolName("targetNamespace"));
String defaultNamespace = ((StringAttributeValue) tarNamespaceAnnAttrVal)
.getValue();
// @GvNIXWebMethod annotations.
for (BodyDeclaration bodyDeclaration : classOrInterfaceDeclaration
.getMembers()) {
if (bodyDeclaration instanceof FieldDeclaration) {
wsExportWsdl.loadWebServiceFieldDeclaration(
declaredByMetadataId,
compilationUnitServices, fieldMetadataList,
bodyDeclaration);
}
else if (bodyDeclaration instanceof MethodDeclaration) {
wsExportWsdl.loadWebServiceMethodDeclaration(
declaredByMetadataId,
compilationUnitServices,
implementedInterface, methodMetadataList,
defaultNamespace, bodyDeclaration);
}
}
javaParserService.createGvNixWebServiceClass(javaType,
gvNixAnnotationList,
GvNIXAnnotationType.WEB_SERVICE, fieldMetadataList,
methodMetadataList, constructorMetadataList,
extendedClassesList, PhysicalTypeCategory.CLASS,
null);
implementationClasses.add(javaType);
}
}
catch (ParseException e) {
throw new IllegalStateException(
"Generated Web Service java file '"
+ webServiceFile.getAbsolutePath()
+ "' has errors:\n" + e.getMessage());
}
catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException(
"Generated Web Service java file '"
+ webServiceFile.getAbsolutePath()
+ "' has errors:\n" + e.getMessage());
}
}
return implementationClasses;
}
/**
* Generate declared java type classes and its inner types from declaration.
*
* @param typeDecl class to convert to JavaType
* @param compUnit Values from class to check
* @param fileDir to check 'package-info.java' annotation values
*/
private void createGvNixXmlElementClass(TypeDeclaration typeDecl,
CompilationUnit compUnit, String fileDir) {
// Compilation unit package
String pkg = compUnit.getPackage().getName().toString();
// Java type to generate from
JavaType type = new JavaType(pkg.concat(".").concat(typeDecl.getName()));
// Initial values for gvNIX xml element annotation creation
PhysicalTypeCategory physicalTypeCategory = PhysicalTypeCategory.CLASS;
List<JavaSymbolName> enumConstants = new ArrayList<JavaSymbolName>();
boolean isEnum = typeDecl instanceof EnumDeclaration;
List<FieldMetadata> fields = new ArrayList<FieldMetadata>();
if (isEnum) {
// Type is an enumeration
// Define physical type as enumeration
physicalTypeCategory = PhysicalTypeCategory.ENUMERATION;
// Add all enumeration constant entries names to a list
for (EnumConstantDeclaration enumDecl : ((EnumDeclaration) typeDecl)
.getEntries()) {
enumConstants.add(new JavaSymbolName(enumDecl.getName()));
}
}
else if (typeDecl instanceof ClassOrInterfaceDeclaration) {
// Type is a class or interface
// For each type member
for (BodyDeclaration body : typeDecl.getMembers()) {
if (body instanceof FieldDeclaration) {
// Member is a field: add gvNIX xml element field annotation
wsExportWsdl.loadFieldFromType(PhysicalTypeIdentifier
.createIdentifier(type, LogicalPath.getInstance(
Path.SRC_MAIN_JAVA, "")),
new WSCompilationUnit(new JavaPackage(pkg), type,
compUnit.getImports(),
new ArrayList<TypeDeclaration>(),
PhysicalTypeCategory.CLASS), fields, body);
}
else if (body instanceof ClassOrInterfaceDeclaration) {
// Member is class or interface: add gvNIX xml element annot
createGvNixXmlElementClass((TypeDeclaration) body,
compUnit, fileDir);
}
}
}
List<AnnotationMetadata> annots = new ArrayList<AnnotationMetadata>();
// ROO annotation to generate get and set methods if is not an enum
if (!isEnum) {
annots.add(new AnnotationMetadataBuilder(
new JavaType(
"org.springframework.roo.addon.javabean.annotations.RooJavaBean"),
new ArrayList<AnnotationAttributeValue<?>>()).build());
}
// Create gvNIX xml element annotation and add it to list
annots.add(getGvNixXmlElementAnnot(typeDecl));
// Create gvNIX web service type with annots, fields, type and enums
javaParserService.createGvNixWebServiceClass(type, annots,
GvNIXAnnotationType.XML_ELEMENT, fields,
new ArrayList<MethodMetadata>(),
new ArrayList<ConstructorMetadata>(),
new ArrayList<JavaType>(), physicalTypeCategory, enumConstants);
}
/**
* Copy package info file from generated folder to sources folder.
*/
private void createPackageInfoClass() {
// If schema package file exists
if (schemaPackage.exists()) {
try {
// Schema package file absolute path
String path = schemaPackage.getAbsolutePath();
// Remove sources dir folder prefix
path = StringUtils.remove(
path,
projectOperations.getPathResolver().getIdentifier(
LogicalPath.getInstance(Path.ROOT, ""),
WsExportWsdl.GENERATED_CXF_SOURCES_DIR));
// Create file into sources folder at same location
fileManager.createOrUpdateTextFileIfRequired(
projectOperations.getPathResolver()
.getIdentifier(
LogicalPath.getInstance(
Path.SRC_MAIN_JAVA, ""), path),
IOUtils.toString(new InputStreamReader(
new FileInputStream(schemaPackage))), true);
}
catch (FileNotFoundException e) {
throw new IllegalStateException(
"Generated 'package-info.java' file '"
+ schemaPackage.getAbsolutePath()
+ "' doesn't exist:\n" + e.getMessage());
}
catch (IOException e) {
throw new IllegalStateException(
"Generated 'package-info.java' file '"
+ schemaPackage.getAbsolutePath()
+ "' has errors:\n" + e.getMessage());
}
}
}
/**
* Retrieve Web Service implemented interface from interface list. TODO to
* be removed?. This method could be useless outside this service.
*
* @param classOrInterfaceDeclaration to retrieve its implemented interface.
* @return {@link ClassOrInterfaceDeclaration} interface that implements
* classOrInterfaceDeclaratio, null if not exists.
* @throws IOException
* @throws ParseException
*/
private ClassOrInterfaceDeclaration getWebServiceInterface(
ClassOrInterfaceDeclaration classOrInterfaceDeclaration)
throws ParseException, IOException {
ClassOrInterfaceDeclaration implementedInterface = null;
List<ClassOrInterfaceType> implementedInterfacesList = classOrInterfaceDeclaration
.getImplements();
String interfaceName;
String fileInterfaceName;
CompilationUnit compilationUnit;
TypeDeclaration type;
for (ClassOrInterfaceType classOrInterfaceType : implementedInterfacesList) {
interfaceName = classOrInterfaceType.getName();
interfaceName = interfaceName.concat(".java");
for (File interfaceFile : webServiceInterfaces) {
fileInterfaceName = wsExportWsdl.getFilename(interfaceFile
.getAbsolutePath());
if (!fileInterfaceName.contentEquals(interfaceName)) {
continue;
}
compilationUnit = JavaParser.parse(interfaceFile);
List<TypeDeclaration> types = compilationUnit.getTypes();
if (types == null) {
continue;
}
type = types.get(0);
if (type instanceof ClassOrInterfaceDeclaration) {
implementedInterface = (ClassOrInterfaceDeclaration) type;
return implementedInterface;
}
}
}
return implementedInterface;
}
/**
* Convert annotation @WebService values from
* {@link ClassOrInterfaceDeclaration} to {@link GvNIXWebService}. TODO to
* be removed from interface?. This method could be useless outside this
* service.
*
* @param classOrInterfaceDeclaration to retrieve values from @WebService
* annotations and convert to {@link GvNIXWebService} values.
* @param implementedInterface Web Service interface.
* @param javaType to retrieve mandatory Annotation attributed with its
* values.
* @return {@link GvNIXWebService} to define in class.
*/
private AnnotationMetadata getGvNIXWebServiceAnnotation(
ClassOrInterfaceDeclaration classOrInterfaceDeclaration,
ClassOrInterfaceDeclaration implementedInterface, JavaType javaType) {
AnnotationMetadata gvNIXWServAnnMdata;
List<AnnotationAttributeValue<?>> gvNIXWServAnnAttr = new ArrayList<AnnotationAttributeValue<?>>();
/*
* Class:
*
* @javax.jws.WebService( serviceName = "TempConvert", portName =
* "TempConvertSoap12", targetNamespace = "http://tempuri.org/",
* wsdlLocation =
* "http://www.w3schools.com/webservices/tempconvert.asmx?WSDL",
* endpointInterface = "org.tempuri.TempConvertSoap") Interface:
*
* @WebService(targetNamespace = "http://tempuri.org/", name =
* "TempConvertSoap") Result:
*
* @WebService(name = "TempConvertSoap",portName = "TempConvertSoap12",
* targetNamespace = "http://tempuri.org/", serviceName =
* "TempConvert");
*
* @WebService(targetNamespace =
* "http://fps.amazonaws.com/doc/2008-09-17/", name =
* "AmazonFPSPortType")
*
* @XmlSeeAlso({ObjectFactory.class})
*
* @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
*/
/*
* @GvNIXWebService address = X name.
*/
// Search for interface annotation attribute values.
List<AnnotationExpr> annotationInterfaceExprList = implementedInterface
.getAnnotations();
for (AnnotationExpr annotationExpr : annotationInterfaceExprList) {
if (annotationExpr instanceof NormalAnnotationExpr) {
NormalAnnotationExpr normalAnnotationExpr = (NormalAnnotationExpr) annotationExpr;
StringAttributeValue addressStringAttributeValue;
if (normalAnnotationExpr.getName().getName()
.contains(webServiceInterface)) {
// Retrieve values.
for (MemberValuePair pair : normalAnnotationExpr.getPairs()) {
if (pair.getName().contentEquals("name")) {
// address
addressStringAttributeValue = new StringAttributeValue(
new JavaSymbolName("name"),
((StringLiteralExpr) pair.getValue())
.getValue());
gvNIXWServAnnAttr.add(addressStringAttributeValue);
break;
}
}
}
else if (normalAnnotationExpr.getName().getName()
.contains(soapBinding)) {
for (MemberValuePair pair : normalAnnotationExpr.getPairs()) {
EnumAttributeValue enumparamStyleAttrVal;
// TODO this is dead code, to Remove it or it's a bug??
// enumparameterStyleAttributeValue = new
// EnumAttributeValue(
// new JavaSymbolName("parameterStyle"),
// new EnumDetails(
// new JavaType(
// "org.gvnix.service.roo.addon.annotations.GvNIXWebService.GvNIXWebServiceParameterStyle"),
// new JavaSymbolName("WRAPPED")));
if (pair.getName().contentEquals("parameterStyle")) {
enumparamStyleAttrVal = new EnumAttributeValue(
new JavaSymbolName("parameterStyle"),
new EnumDetails(
new JavaType(
"org.gvnix.service.roo.addon.annotations.GvNIXWebService.GvNIXWebServiceParameterStyle"),
new JavaSymbolName(
((FieldAccessExpr) pair
.getValue())
.getField())));
gvNIXWServAnnAttr.add(enumparamStyleAttrVal);
}
}
}
}
}
/*
* @GvNIXWebService name = class portName. serviceName = class
* serviceName. targetNamespace = class targetNamespace.
*/
List<AnnotationExpr> annotationExprList = classOrInterfaceDeclaration
.getAnnotations();
for (AnnotationExpr annotationExpr : annotationExprList) {
if (annotationExpr instanceof NormalAnnotationExpr) {
NormalAnnotationExpr normalAnnotationExpr = (NormalAnnotationExpr) annotationExpr;
StringAttributeValue nameStringAttributeValue;
StringAttributeValue tarNamespaceStrAttrVal;
StringAttributeValue servNameStrAttrVal;
// Retrieve values.
for (MemberValuePair pair : normalAnnotationExpr.getPairs()) {
if (pair.getName().contentEquals("serviceName")) {
// serviceName
servNameStrAttrVal = new StringAttributeValue(
new JavaSymbolName("serviceName"),
((StringLiteralExpr) pair.getValue())
.getValue());
gvNIXWServAnnAttr.add(servNameStrAttrVal);
continue;
}
else if (pair.getName().contentEquals("targetNamespace")) {
// targetNamespace
tarNamespaceStrAttrVal = new StringAttributeValue(
new JavaSymbolName("targetNamespace"),
((StringLiteralExpr) pair.getValue())
.getValue());
gvNIXWServAnnAttr.add(tarNamespaceStrAttrVal);
continue;
}
else if (pair.getName().contentEquals("portName")) {
// name
nameStringAttributeValue = new StringAttributeValue(
new JavaSymbolName("address"),
((StringLiteralExpr) pair.getValue())
.getValue());
gvNIXWServAnnAttr.add(nameStringAttributeValue);
continue;
}
}
}
}
// fullyQualifiedTypeName
StringAttributeValue fullyQualStrAttrVal = new StringAttributeValue(
new JavaSymbolName("fullyQualifiedTypeName"),
javaType.getFullyQualifiedTypeName());
gvNIXWServAnnAttr.add(fullyQualStrAttrVal);
// exported
BooleanAttributeValue exportedAttributeValue = new BooleanAttributeValue(
new JavaSymbolName("exported"), true);
gvNIXWServAnnAttr.add(exportedAttributeValue);
// Create GvNIXWebService annotation.
gvNIXWServAnnMdata = new AnnotationMetadataBuilder(new JavaType(
GvNIXWebService.class.getName()), gvNIXWServAnnAttr).build();
return gvNIXWServAnnMdata;
}
/**
* Convert annotation @XmlElement values to GvNIXXmlElement.
* <p>
* Searches for Jaxb annotations in {@link ClassOrInterfaceDeclaration} to
* convert values to {@link GvNIXXmlElement}.
* </p>
*
* @param typeDecl To retrieve values from @XmlElement annotations
* @return {@link GvNIXXmlElement} to define in class
*/
private AnnotationMetadata getGvNixXmlElementAnnot(TypeDeclaration typeDecl) {
// Attribute value list.
List<AnnotationAttributeValue<?>> attrs = new ArrayList<AnnotationAttributeValue<?>>();
boolean isNamespace = false;
boolean isPropOrder = false;
for (AnnotationExpr typeAnnot : typeDecl.getAnnotations()) {
if (typeAnnot instanceof NormalAnnotationExpr) {
NormalAnnotationExpr normalAnnot = (NormalAnnotationExpr) typeAnnot;
String name = normalAnnot.getName().getName();
List<MemberValuePair> pairs = normalAnnot.getPairs();
if (name.contains(xmlRootElement)) {
// It's @XmlRootElement
wsExportWsdl.addNameAttr(attrs, pairs);
}
else if (name.contains(xmlType)) {
// It's @XmlType
for (MemberValuePair pair : pairs) {
if (pair.getName().contentEquals("name")) {
// @XmlType.name
wsExportWsdl.addXmlTypeNameAttr(attrs, pair);
}
else if (pair.getName().contentEquals("propOrder")) {
// @XmlType.propOrder
wsExportWsdl.addElementListAttr(attrs, pair);
isPropOrder = true;
}
else if (pair.getName().contentEquals("namespace")) {
// @XmlType.namespace
wsExportWsdl.addNamespaceAttr(attrs, pair);
isNamespace = true;
}
}
}
}
}
// Check correct values for @GvNIXXmlElement.
if (!isPropOrder) {
wsExportWsdl.addElementListAttr(attrs);
}
if (!isNamespace) {
addNamespaceAttr(attrs);
}
wsExportWsdl.addExportedAttr(attrs);
wsExportWsdl.addEnumElementAttr(typeDecl, attrs);
// Create annotation
return new AnnotationMetadataBuilder(new JavaType(
GvNIXXmlElement.class.getName()), attrs).build();
}
private void addNamespaceAttr(List<AnnotationAttributeValue<?>> annotAttrs) {
try {
String ns = "";
boolean exists = false;
List<AnnotationExpr> annots = JavaParser.parse(schemaPackage)
.getPackage().getAnnotations();
for (AnnotationExpr annot : annots) {
if (annot instanceof NormalAnnotationExpr) {
NormalAnnotationExpr normalAnnot = (NormalAnnotationExpr) annot;
if (normalAnnot.getName().toString()
.contains("javax.xml.bind.annotation.XmlSchema")) {
// @XmlSchema
for (MemberValuePair pair : normalAnnot.getPairs()) {
if (pair.getName().contentEquals("namespace")) {
ns = ((StringLiteralExpr) pair.getValue())
.getValue();
exists = true;
break;
}
}
}
}
if (exists) {
break;
}
}
// look for @XmlSchema
annotAttrs.add(new StringAttributeValue(new JavaSymbolName(
"namespace"), ns));
}
catch (ParseException e) {
throw new IllegalStateException(
"Generated Xml Element service java file has errors:\n"
+ e.getMessage());
}
catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException(
"Generated Xml Element service java file has errors:\n"
+ e.getMessage());
}
}
}