uk.co.jemos.protomak.engine.impl.XsomXsdToProtoDomainConversionServiceImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of protomak-engine Show documentation
Show all versions of protomak-engine Show documentation
This is PROTOMAK engine to convert integration technology files such as XML and Jonas into .proto files
The newest version!
/**
*
*/
package uk.co.jemos.protomak.engine.impl;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import uk.co.jemos.protomak.engine.api.ConversionService;
import uk.co.jemos.protomak.engine.api.ProtoSerialisationService;
import uk.co.jemos.protomak.engine.api.XsomComplexTypeProcessor;
import uk.co.jemos.protomak.engine.exceptions.ProtomakEngineSerialisationError;
import uk.co.jemos.protomak.engine.exceptions.ProtomakXsdToProtoConversionError;
import uk.co.jemos.protomak.engine.utils.ProtomakEngineConstants;
import uk.co.jemos.protomak.engine.utils.ProtomakEngineHelper;
import uk.co.jemos.xsds.protomak.proto.MessageAttributeOptionalType;
import uk.co.jemos.xsds.protomak.proto.MessageAttributeType;
import uk.co.jemos.xsds.protomak.proto.MessageType;
import uk.co.jemos.xsds.protomak.proto.ProtoType;
import com.sun.xml.xsom.XSComplexType;
import com.sun.xml.xsom.XSElementDecl;
import com.sun.xml.xsom.XSSchemaSet;
import com.sun.xml.xsom.XSType;
import com.sun.xml.xsom.parser.XSOMParser;
/**
* XSD to Proto conversion service.
*
*
* The mail goal of this class is to convert a given XSD to one or more proto
* files.
*
*
* @author mtedone
*
*/
public class XsomXsdToProtoDomainConversionServiceImpl implements
ConversionService {
// ------------------->> Constants
/** The application logger. */
public static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
.getLogger(XsomXsdToProtoDomainConversionServiceImpl.class);
// ------------------->> Instance / Static variables
/** The processor for complex types */
private final XsomComplexTypeProcessor complexTypeProcessor;
/** The proto serialisation service */
private final ProtoSerialisationService protoSerialisationService;
/** Error Handler */
private ErrorHandler errorHandler = new ProtomakErrorHandler();
/** The XSOM Schema parser */
private XSOMParser parser;
// ------------------->> Constructors
/**
* Default constructor.
*/
public XsomXsdToProtoDomainConversionServiceImpl() {
this(XsomDefaultComplexTypeProcessor.getInstance(),
PojoToProtoSerialisationServiceImpl.getInstance());
}
/**
* Full constructor
*
* @param complexTypeProcessor
* The complex type processor
*
* @param protoSerialisationService
* The proto serialisation service.
*/
public XsomXsdToProtoDomainConversionServiceImpl(
XsomComplexTypeProcessor complexTypeProcessor,
ProtoSerialisationService protoSerialisationService) {
super();
this.complexTypeProcessor = complexTypeProcessor;
this.protoSerialisationService = protoSerialisationService;
}
// ------------------->> Public methods
/**
* {@inheritDoc}
*
* @throws IllegalArgumentException
* If the {@code inputPath} does not exist.
* @throws ProtomakXsdToProtoConversionError
* If an error occured while parsing the file
*
* @throws ProtomakEngineSerialisationError
* If an error occurred while serialisation the
* {@link ProtoType} to an output destination.
*/
public void generateProtoFiles(String inputPath, String outputPath) {
File inputFilePath = new File(inputPath);
if (!inputFilePath.exists()) {
String errMsg = "The XSD input file: "
+ inputFilePath.getAbsolutePath()
+ " does not exist. Throwing an exception.";
LOG.error(errMsg);
throw new IllegalArgumentException(errMsg);
}
ProtoType proto = new ProtoType();
try {
LOG.debug("Is parser null? " + parser == null);
if (parser == null) {
parser = new XSOMParser();
}
parser.setErrorHandler(errorHandler);
parser.parse(inputFilePath);
XSSchemaSet sset = parser.getResult();
if (null == sset) {
throw new IllegalStateException(
"An error occurred while parsing the schema. Aborting.");
}
LOG.info("Processing all complex types in the XSD...");
this.manageComplexTypes(proto, sset, inputPath);
LOG.info("Processing all elements in the XSD...");
this.manageElements(proto, sset, inputPath);
// Sorts the Message Types in order of their names
LOG.info("Sorting Message Types based on their names...");
Collections.sort(proto.getMessage(),
ProtomakEngineConstants.MESSAGE_TYPE_COMPARATOR);
String protoFileName = ProtomakEngineHelper
.extractProtoFileNameFromXsdName(inputFilePath.getName());
File outputDir = new File(outputPath);
protoSerialisationService.writeProtoFile(protoFileName, outputDir,
proto);
LOG.info("Proto file: " + protoFileName + " written to "
+ outputPath);
} catch (SAXException e) {
String errMsg = "A SAX Exception occurred while parsing the XSD Schema.";
LOG.error(errMsg, e);
throw new ProtomakXsdToProtoConversionError(e);
} catch (IOException e) {
String errMsg = "An IO Exception occurred while parsing the XSD Schema.";
LOG.error(errMsg, e);
throw new ProtomakXsdToProtoConversionError(e);
} finally {
// Nasty, but for bulk generation, apparently the parser retains
// previous state, so we need to create a new one each time. We do
// this at the end not to step on the toes of mock parsers set by
// tests
parser = new XSOMParser();
}
}
/**
* {@inheritDoc}
*/
public void generateProtoFiles(String inputFolder, String outputFolder,
final String fileExtension) {
File inputFolderFile = new File(inputFolder);
if (!inputFolderFile.exists()) {
throw new IllegalArgumentException("The input folder: "
+ inputFolderFile.getAbsolutePath() + " does not exist!");
}
FilenameFilter filenameFilter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(fileExtension);
}
};
File[] inputFiles = inputFolderFile.listFiles(filenameFilter);
for (File file : inputFiles) {
LOG.info("Invoking conversion for file: " + file.getAbsolutePath());
this.generateProtoFiles(file.getAbsolutePath(), outputFolder);
}
}
// ------------------->> Getters / Setters
/**
* Setter method mainly for testing to inject mocks.
*
* @param parser
* the parser to set
*/
public void setParser(XSOMParser parser) {
this.parser = parser;
}
// ------------------->> Private methods
/**
* It goes through all complex types in the XSD and for each one it creates
* a message in proto.
*
* @param proto
* The proto object
* @param schema
* The representation of the XSD Schema
* @param inputPath
* The full path to the XSD file
*/
private void manageComplexTypes(ProtoType proto, XSSchemaSet schema,
String inputPath) {
List protoMessages = proto.getMessage();
Iterator complexTypesIterator = schema
.iterateComplexTypes();
XSComplexType complexType = null;
while (complexTypesIterator.hasNext()) {
complexType = complexTypesIterator.next();
if (complexType.getName().equals(
ProtomakEngineConstants.ANY_TYPE_NAME)) {
LOG.debug("Skipping anyType: " + complexType.getName());
continue;
}
if (null == proto.getPackage()) {
String packageName = ProtomakEngineHelper
.convertTargetNsToProtoPackageName(complexType
.getTargetNamespace());
LOG.info("Proto package will be: " + packageName);
proto.setPackage(packageName);
}
LOG.debug("Processing complex type: " + complexType.getName());
complexTypeProcessor.processComplexType(protoMessages, complexType,
inputPath);
}
LOG.info("All complex types have been processed.");
}
/**
* It goes through all elements defined in the XSD and for each one it
* creates a default message.
*
* @param proto
* The root proto object
* @param schema
* The XSD schema representation
* @param inputPath
* The full path to the XSD file
*/
private void manageElements(ProtoType proto, XSSchemaSet schema,
String inputPath) {
// Iterates over the elements
Iterator declaredElementsIterator = schema
.iterateElementDecls();
int messageSuffix = 1;
while (declaredElementsIterator.hasNext()) {
MessageType msgType = new MessageType();
XSElementDecl element = declaredElementsIterator.next();
XSType type = element.getType();
if (type.isLocal()) {
LOG.debug("Type for element: " + element.getName()
+ " is local");
TypeVisitor visitor = new TypeVisitor(proto.getMessage(),
msgType, inputPath);
type.visit(visitor);
}
String nameForAnonymousType = ProtomakEngineHelper
.getMessageTypeName(element.getName(), inputPath);
msgType.setName(nameForAnonymousType);
List msgAttributes = msgType
.getMsgAttribute();
MessageAttributeType msgAttrType = ProtomakEngineHelper
.getMessageAttribute(element, messageSuffix,
MessageAttributeOptionalType.REQUIRED);
msgAttributes.add(msgAttrType);
messageSuffix++;
proto.getMessage().add(msgType);
if (null == proto.getPackage()) {
String packageName = ProtomakEngineHelper
.convertTargetNsToProtoPackageName(element
.getTargetNamespace());
LOG.info("Proto package will be: " + packageName);
proto.setPackage(packageName);
}
}
}
// ------------------->> equals() / hashcode() / toString()
// ------------------->> Inner classes
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy