/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* 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
*******************************************************************************/
package org.ebayopensource.turmeric.tools.codegen.schema;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.ebayopensource.turmeric.runtime.common.impl.internal.schema.FlatSchemaComplexTypeImpl;
import org.ebayopensource.turmeric.runtime.common.impl.internal.schema.FlatSchemaElementDeclImpl;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import org.ebayopensource.turmeric.tools.codegen.exception.BrokenSchemaException;
import org.ebayopensource.turmeric.tools.codegen.exception.UnsupportedSchemaException;
import org.ebayopensource.turmeric.tools.codegen.util.CodeGenUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import com.sun.tools.xjc.ErrorReceiver;
/**
* @author ichernyshev
*/
public abstract class FlatSchemaLoader {
protected static final String XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
protected static final String XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance";
protected static final Object XML_SCHEMA_DATATYPES = "http://www.w3.org/2001/XMLSchema-datatypes";
protected static final String XML_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace";
private final ErrorReceiverImpl m_errorReceiver = new ErrorReceiverImpl();
private String m_schemaName;
public static FlatSchemaLoader createInstanceFromWsdl(String uri)
throws UnsupportedSchemaException
{
FlatSchemaLoader result = new XSOMFlatSchemaLoader();
result.m_schemaName = uri;
result.init(uri);
Document wsdl = result.parseXml(uri);
/* If the WSDL has import element for importing external XSDs using the "schemLocation" attribute and if the value for the attribute
* is not a absolute/relative path , then it has to be manually set so that the DOMForestScanner.scan method does not throw an error.
* This is more of a work-around fix , since the DOMForestScanner is not calling the call back method provided thru the setEntityResolver method
* (for the underlying parser instance)
*/
NodeList imports = wsdl.getElementsByTagNameNS(XML_SCHEMA, "import");
if(imports.getLength() > 0)
processWSDLImportsAndIncludes(wsdl,uri,imports);
NodeList includes = wsdl.getElementsByTagNameNS(XML_SCHEMA, "include");
if(includes.getLength() > 0)
processWSDLImportsAndIncludes(wsdl,uri,includes);
NodeList schemas = wsdl.getElementsByTagNameNS(XML_SCHEMA, "schema");
List<Element> schemas2 = new ArrayList<Element>();
for (int i=0; i<schemas.getLength(); i++) {
Element schema = (Element)schemas.item(i);
schemas2.add(schema);
}
result.parseSchemaRootElements(schemas2,imports);
result.checkForErrors();
result.load();
result.checkForErrors();
return result;
}
private static void processWSDLImportsAndIncludes(Document wsdl,String uri,NodeList imports){
URL wsdlURL = null;
File wsdlFile = null;
String wsdlBasePath = null;
String wsdlBaseAbsolutePath = null;
try {
wsdlFile = new File(uri);
if (wsdlFile.isFile() || uri.indexOf(':') == -1) {
wsdlURL = new URL("file", null, 0, uri);
wsdlBaseAbsolutePath = wsdlFile.getAbsolutePath();
wsdlBaseAbsolutePath = wsdlBaseAbsolutePath.replace("\\", "/");
int lastPos = wsdlBaseAbsolutePath.lastIndexOf("/");
if(lastPos != -1)
wsdlBaseAbsolutePath = wsdlBaseAbsolutePath.substring(0,lastPos + 1);
} else {
wsdlURL = new URL(uri);
}
wsdlBasePath = wsdlURL.toString();
wsdlBasePath = wsdlBasePath.replace("\\","/");
int lastPos = wsdlBasePath.lastIndexOf("/");
if(lastPos != -1)
wsdlBasePath = wsdlBasePath.substring(0,lastPos + 1);
} catch (MalformedURLException e) {}
for (int i=0; i<imports.getLength(); i++) {
Element impElem = (Element)imports.item(i);
String importFileLocation = impElem.getAttribute("schemaLocation");
if(! isEmptyString(importFileLocation)){
try {
new URL(importFileLocation);
} catch (MalformedURLException e) {
//If a malformed URL comes then figure out whether that could be a file in the local system
File importFile = new File(importFileLocation);
if(!importFile.isAbsolute()){
String wsdlBasePathToBeUsed = wsdlBaseAbsolutePath;
if(CodeGenUtil.isEmptyString(wsdlBasePathToBeUsed))
wsdlBasePathToBeUsed = wsdlBasePath;
if(!CodeGenUtil.isEmptyString(wsdlBasePathToBeUsed)){
importFileLocation = importFileLocation.replace("\\","/");
if(wsdlBasePathToBeUsed.endsWith("/") && importFileLocation.startsWith("/"))
wsdlBasePathToBeUsed = wsdlBasePathToBeUsed.substring(0,wsdlBasePathToBeUsed.length() - 1 );
importFileLocation = wsdlBasePathToBeUsed + importFileLocation;
}
importFileLocation = importFileLocation.replace("\\","/");
importFile = new File(importFileLocation);
if(importFile.exists())
importFileLocation = importFile.toURI().toString();
impElem.setAttribute("schemaLocation",importFileLocation);
}
}
}
}
}
private static boolean isEmptyString(String str) {
return (str == null || str.trim().length() == 0);
}
public static FlatSchemaLoader createInstanceFromXsd(File[] files)
throws UnsupportedSchemaException
{
FlatSchemaLoader result = new XSOMFlatSchemaLoader();
result.m_schemaName = (files.length != 0 ? files[0].getParent(): "No_Files");
result.init(result.m_schemaName);
result.parseSchemaFromFiles(files);
result.checkForErrors();
result.load();
result.checkForErrors();
return result;
}
public static FlatSchemaLoader createEmptyInstance()
{
FlatSchemaLoader result = new EmptyFlatSchemaLoader();
result.m_schemaName = "Empty";
return result;
}
public abstract List<FlatSchemaComplexTypeImpl> getComplexTypes();
public abstract Map<QName,FlatSchemaElementDeclImpl> getRootElements();
protected final Document parseXml(String fileName) throws BrokenSchemaException {
System.out.println("Loading XML document '" + fileName + "'"); //KEEPME
InputStream is = null;
Document result;
try {
URL url;
File file = new File(fileName);
if (file.isFile() || fileName.indexOf(':') == -1) {
url = new URL("file", null, 0, fileName);
} else {
url = new URL(fileName);
}
is = url.openStream();
result = parseXml(is);
} catch (MalformedURLException e) {
throw new BrokenSchemaException("File is not found or URL is broken for '" +
fileName + "' : " + e.toString(), e);
} catch (IOException e) {
throw new BrokenSchemaException("Unable to read '" + fileName + "' : " + e.toString(), e);
} finally {
CodeGenUtil.closeQuietly(is);
}
return result;
}
private Document parseXml(InputStream is) throws BrokenSchemaException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
Document result;
try {
DocumentBuilder builder = factory.newDocumentBuilder();
ErrorHandler errorHandler = m_errorReceiver;
builder.setErrorHandler(errorHandler);
result = builder.parse(is);
} catch (ParserConfigurationException e) {
throw new BrokenSchemaException(e.toString(), e);
} catch (SAXException e) {
throw new BrokenSchemaException(e.toString(), e);
} catch (IOException e) {
throw new BrokenSchemaException(e.toString(), e);
}
return result;
}
private void checkForErrors() throws UnsupportedSchemaException {
if (!m_errorReceiver.m_errors.isEmpty()) {
Exception e = m_errorReceiver.m_errors.get(0);
throw new UnsupportedSchemaException("Error parsing schema in " +
m_schemaName + ": " + e.toString(), e);
}
}
protected final ErrorReceiver getErrorReceiver() {
return m_errorReceiver;
}
protected abstract void init(String uri) throws UnsupportedSchemaException;
protected abstract void load() throws UnsupportedSchemaException;
protected abstract void parseSchemaRootElements(List<Element> schemas,NodeList imports) throws UnsupportedSchemaException;
protected abstract void parseSchemaFromFiles(File[] files) throws UnsupportedSchemaException;
private class ErrorReceiverImpl extends ErrorReceiver {
List<SAXParseException> m_errors = new ArrayList<SAXParseException>();
List<SAXParseException> m_warnings = new ArrayList<SAXParseException>();
public void error(SAXParseException e) {
LogManager.getInstance(FlatSchemaLoader.class).log(Level.SEVERE,
"Error parsing schema in " + m_schemaName + ": " + e.toString(), e);
m_errors.add(e);
}
public void fatalError(SAXParseException e) {
error(e);
}
public void warning(SAXParseException e) {
LogManager.getInstance(FlatSchemaLoader.class).log(Level.WARNING,
"Warning parsing schema in " + m_schemaName + ": " + e.toString(), e);
m_warnings.add(e);
}
public void info(SAXParseException exception) {
}
}
private static class EmptyFlatSchemaLoader extends FlatSchemaLoader {
@Override
public List<FlatSchemaComplexTypeImpl> getComplexTypes() {
return new ArrayList<FlatSchemaComplexTypeImpl>();
}
@Override
public Map<QName,FlatSchemaElementDeclImpl> getRootElements() {
return new HashMap<QName,FlatSchemaElementDeclImpl>();
}
@Override
protected void init(String uri) throws UnsupportedSchemaException {
}
@Override
protected void load() throws UnsupportedSchemaException {
}
@Override
protected void parseSchemaRootElements(List<Element> schemas,NodeList imports) throws UnsupportedSchemaException {
}
@Override
protected void parseSchemaFromFiles(File[] files) throws UnsupportedSchemaException {
}
}
}