Skip to content

Commit

Permalink
First working function to recursively resolve, download and unmarshal…
Browse files Browse the repository at this point in the history
… external xml schemas
  • Loading branch information
c4milo committed Dec 27, 2013
1 parent d5f3aa8 commit ce6509e
Showing 1 changed file with 160 additions and 44 deletions.
204 changes: 160 additions & 44 deletions gowsdl.go
Original file line number Diff line number Diff line change
@@ -1,46 +1,81 @@
package main

import (
"crypto/tls"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
"sync"
)

const maxRecursion uint8 = 5

type GoWsdl struct {
file, pkg string
logger *log.Logger
wsdl *Wsdl
file, pkg string
wsdl *Wsdl
resolvedXsdExternals map[string]bool
currentRecursionLevel uint8
}

var cacheDir = os.TempDir() + "gowsdl-cache"

func init() {
err := os.MkdirAll(cacheDir, 0700)
if err != nil {
log.Fatalf("Unable to reate cache directory")
}
}

func downloadFile(url string) ([]byte, error) {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
client := &http.Client{Transport: tr}

resp, err := client.Get(url)
if err != nil {
return nil, err
}

defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

return data, nil
}

func NewGoWsdl(file, pkg string, logger *log.Logger) (*GoWsdl, error) {
func NewGoWsdl(file, pkg string) (*GoWsdl, error) {
file = strings.TrimSpace(file)
if file == "" {
logger.Fatalln("WSDL file is required to generate Go proxy")
log.Fatalln("WSDL file is required to generate Go proxy")
}

pkg = strings.TrimSpace(pkg)
if pkg == "" {
pkg = "main"
}

if logger == nil {
logger = log.New(os.Stdout, "", 0)
}

return &GoWsdl{
file: file,
pkg: pkg,
logger: logger,
file: file,
pkg: pkg,
}, nil
}

func (g *GoWsdl) Start() (map[string][]byte, error) {
gocode := make(map[string][]byte)

err := g.Unmarshal()
err := g.unmarshal()
if err != nil {
return nil, err
}
Expand All @@ -52,9 +87,20 @@ func (g *GoWsdl) Start() (map[string][]byte, error) {
defer wg.Done()
var err error

gocode["types"], err = g.GenTypes()
gocode["types"], err = g.genTypes()
if err != nil {
log.Println(err)
}
}()

wg.Add(1)
go func() {
defer wg.Done()
var err error

gocode["messages"], err = g.genMessages()
if err != nil {
g.logger.Println(err)
log.Println(err)
}
}()

Expand All @@ -63,9 +109,9 @@ func (g *GoWsdl) Start() (map[string][]byte, error) {
defer wg.Done()
var err error

gocode["operations"], err = g.GenOperations()
gocode["operations"], err = g.genOperations()
if err != nil {
g.logger.Println(err)
log.Println(err)
}
}()

Expand All @@ -74,9 +120,9 @@ func (g *GoWsdl) Start() (map[string][]byte, error) {
defer wg.Done()
var err error

gocode["proxy"], err = g.GenSoapProxy()
gocode["proxy"], err = g.genSoapProxy()
if err != nil {
g.logger.Println(err)
log.Println(err)
}
}()

Expand All @@ -85,15 +131,24 @@ func (g *GoWsdl) Start() (map[string][]byte, error) {
return gocode, nil
}

func (g *GoWsdl) Unmarshal() error {
g.logger.Printf("Using %s...\n", g.file)
func (g *GoWsdl) unmarshal() error {
var data []byte

//g.file is URL or local file?
//if URL, download!
parsedUrl, err := url.Parse(g.file)
if parsedUrl.Scheme == "" {
log.Printf("Reading file %s...\n", g.file)

data, err := ioutil.ReadFile(g.file)
if err != nil {
return err
data, err = ioutil.ReadFile(g.file)
if err != nil {
return err
}
} else {
log.Printf("Downloading %s...\n", g.file)

data, err = downloadFile(g.file)
if err != nil {
return err
}
}

g.wsdl = &Wsdl{}
Expand All @@ -102,49 +157,110 @@ func (g *GoWsdl) Unmarshal() error {
return err
}

//Resolve wsdl imports
//Resolve xsd includes
//Resolve xsd imports
for _, schema := range g.wsdl.Types.Schemas {
err = g.resolveXsdExternals(schema, parsedUrl)
if err != nil {
return err
}
}

return nil
}

func (g *GoWsdl) GenTypes() ([]byte, error) {
if g.wsdl == nil {
g.logger.Fatalln("You have to unmarshal the WSDL file first")
func (g *GoWsdl) resolveXsdExternals(schema *XsdSchema, url *url.URL) error {

for _, incl := range schema.Includes {
location, err := url.Parse(incl.SchemaLocation)
if err != nil {
return err
}

_, schemaName := filepath.Split(location.Path)
if g.resolvedXsdExternals[schemaName] {
continue
}

schemaLocation := location.String()
if !location.IsAbs() {
if !url.IsAbs() {
return errors.New(fmt.Sprintf("Unable to resolve external schema %s through WSDL URL %s", schemaLocation, url))
}
schemaLocation = url.Scheme + "://" + url.Host + schemaLocation
}

log.Printf("Downloading external schema: %s\n", schemaLocation)

data, err := downloadFile(schemaLocation)
newschema := &XsdSchema{}

err = xml.Unmarshal(data, newschema)
if err != nil {
return err
}

if len(newschema.Includes) > 0 &&
maxRecursion > g.currentRecursionLevel {

g.currentRecursionLevel++

//log.Printf("Entering recursion %d\n", g.currentRecursionLevel)
g.resolveXsdExternals(newschema, url)
}

g.wsdl.Types.Schemas = append(g.wsdl.Types.Schemas, newschema)

if g.resolvedXsdExternals == nil {
g.resolvedXsdExternals = make(map[string]bool, maxRecursion)
}
g.resolvedXsdExternals[schemaName] = true
}

// for _, imp := range schema.Imports {

// }
return nil
}

func (g *GoWsdl) genTypes() ([]byte, error) {
//element > complexType

for _, schema := range g.wsdl.Types.Schemas {
g.logger.Println(schema.XMLName)
embed := 0
refcount := 0
for _, el := range schema.Elements {
if el.Type != "" {
embed++
} else {
refcount++
}
}

// log.Printf("embedded types: %d\n", embed)
// log.Printf("referenced types: %d\n", refcount)
// for _, element := range schema.Elements {
// g.logger.Printf("Type: %s\n", element.Name)
// }
g.logger.Printf("Total types: %d\n", len(schema.Elements))

}

return nil, nil
}

func (g *GoWsdl) GenOperations() ([]byte, error) {
if g.wsdl == nil {
g.logger.Fatalln("You have to unmarshal the WSDL file first")
}

func (g *GoWsdl) genOperations() ([]byte, error) {
for _, pt := range g.wsdl.PortTypes {
// for _, o := range pt.Operations {
// g.logger.Printf("Operation: %s", o.Name)
// }
g.logger.Printf("Total ops: %d\n", len(pt.Operations))
log.Printf("Total ops: %d\n", len(pt.Operations))
}

return nil, nil
}

func (g *GoWsdl) GenSoapProxy() ([]byte, error) {
if g.wsdl == nil {
g.logger.Fatalln("You have to unmarshal the WSDL file first")
}
func (g *GoWsdl) genMessages() ([]byte, error) {
return nil, nil
}

func (g *GoWsdl) genSoapProxy() ([]byte, error) {
return nil, nil
}

0 comments on commit ce6509e

Please sign in to comment.