Uploaded image for project: 'Spring Web Services'
  1. Spring Web Services
  2. SWS-281

add support for imported xsd in static wsdl as well as xsd's that import other xsd's

    Details

    • Type: New Feature
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.5.1
    • Component/s: Core
    • Labels:
      None
    • Environment:
      Spring WS 1.0.2

      Description

      Currently, Spring WS does not seem to have support for serving up xsd's that are imported into static wsdl. There is also no support for xsd's that import other xsd's. Both situations are considered best practices by schema and wsdl designers.

      The schemaLocation attribute should be transformed in the same way that the location attribute is transformed for wsdl's today to include the request specific server info depending on where the application is deployed.

      Usage Examples:

      wsdl (with imported xsd)
      request
      http://localhost:7001/Services/8.02/Example?wsdl

      response (partial)
      <wsdl:definitions name="Example" targetNamespace="http://services">
      <wsdl:types>
      <xs:schema>
      <xs:import namespace="http://customer/types" schemaLocation="http://localhost:7001/Services/8.02/Example?Customer.xsd"/>
      </xs:schema>
      </wsdl:types>

      xsd (with imported xsd)
      request
      http://localhost:7001/Services/8.02/Example?Customer.xsd

      response (partial)
      <xs:schema targetNamespace="http://customer/types">
      <xs:import namespace="http://order/types" schemaLocation="http://localhost:7001/Services/8.02/Example?Order.xsd"/>

        Issue Links

          Activity

          lafondoo Mark LaFond created issue -
          Hide
          lafondoo Mark LaFond added a comment -

          I've attached a .zip that contains source code for a full working example. Please see the readme.txt for details.

          I followed the pattern already in use by the WsdlDefinition code. Although it seems a little clunky to define .xsd's individually in the spring config file it does allow for the resource location to be completely configurable. In my case, I'm actually using Xml Beans to create a separate .jar via Maven so I can simply get the xsd's and wsdl's off the classpath instead of duplicating them within the .war project in maven.

          Show
          lafondoo Mark LaFond added a comment - I've attached a .zip that contains source code for a full working example. Please see the readme.txt for details. I followed the pattern already in use by the WsdlDefinition code. Although it seems a little clunky to define .xsd's individually in the spring config file it does allow for the resource location to be completely configurable. In my case, I'm actually using Xml Beans to create a separate .jar via Maven so I can simply get the xsd's and wsdl's off the classpath instead of duplicating them within the .war project in maven.
          lafondoo Mark LaFond made changes -
          Field Original Value New Value
          Attachment springws.zip [ 13615 ]
          arjen.poutsma Arjen Poutsma made changes -
          Fix Version/s 1.5 RC1 [ 10652 ]
          arjen.poutsma Arjen Poutsma made changes -
          Link This issue is related to SWS-271 [ SWS-271 ]
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Hey Mark,

          The XsdDefinition interface in the zip looks interesting, I am working on putting it into 1.5. Not sure whether the schema translation feature will be added, because there is also SWS-271 to think about. My current thoughts to solve this are as follows:

          • Inline all imported XSDs into the WSDL, getting rid of the schemaLocation of the import tag. .NET 3.0 uses a similar trick.
          • inline all included XSDs into the including XSD, getting rid of the include altogether.

          In the end, you still have the advantage of separate schema files, but they are served as one WSDL. I am interested in hearing your thoughts on this solution.

          Before I can add the code in the attached zip to the code base, I need your formal approval to releasing this code under the Apache License version 2. I know that you added the license tags to the Java files already, so I suppose you have no issue with it, but I do need that approval.

          A comment in this issue will do.

          Thanks

          Show
          arjen.poutsma Arjen Poutsma added a comment - Hey Mark, The XsdDefinition interface in the zip looks interesting, I am working on putting it into 1.5. Not sure whether the schema translation feature will be added, because there is also SWS-271 to think about. My current thoughts to solve this are as follows: Inline all imported XSDs into the WSDL, getting rid of the schemaLocation of the import tag. .NET 3.0 uses a similar trick. inline all included XSDs into the including XSD, getting rid of the include altogether. In the end, you still have the advantage of separate schema files, but they are served as one WSDL. I am interested in hearing your thoughts on this solution. Before I can add the code in the attached zip to the code base, I need your formal approval to releasing this code under the Apache License version 2. I know that you added the license tags to the Java files already, so I suppose you have no issue with it, but I do need that approval. A comment in this issue will do. Thanks
          arjen.poutsma Arjen Poutsma made changes -
          Link This issue depends on SWS-179 [ SWS-179 ]
          arjen.poutsma Arjen Poutsma made changes -
          Link This issue depends on SWS-179 [ SWS-179 ]
          arjen.poutsma Arjen Poutsma made changes -
          Link This issue is related to SWS-179 [ SWS-179 ]
          arjen.poutsma Arjen Poutsma made changes -
          Status Open [ 1 ] In Progress [ 3 ]
          arjen.poutsma Arjen Poutsma made changes -
          Link This issue is duplicated by SWS-250 [ SWS-250 ]
          Hide
          ray_harrison Ray Harrison added a comment -

          Hi Arjen,

          Mr. LaFond is soaking up the sun in Hawaii this week but should be able to provide his approval next week. Here at Comcast, we are happily using 1.02 and 1.03 variants using Mark's additions and would welcome the solution you propose or a mixture of the two.

          Cheers
          Ray Harrison

          Show
          ray_harrison Ray Harrison added a comment - Hi Arjen, Mr. LaFond is soaking up the sun in Hawaii this week but should be able to provide his approval next week. Here at Comcast, we are happily using 1.02 and 1.03 variants using Mark's additions and would welcome the solution you propose or a mixture of the two. Cheers Ray Harrison
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          I've implemented the inlining approach, and it seems to work well.

          Show
          arjen.poutsma Arjen Poutsma added a comment - I've implemented the inlining approach, and it seems to work well.
          arjen.poutsma Arjen Poutsma made changes -
          Status In Progress [ 3 ] Resolved [ 5 ]
          Resolution Fixed [ 1 ]
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Closing issues in 1.5 RC1.

          Show
          arjen.poutsma Arjen Poutsma added a comment - Closing issues in 1.5 RC1.
          arjen.poutsma Arjen Poutsma made changes -
          Status Resolved [ 5 ] Closed [ 6 ]
          Hide
          lafondoo Mark LaFond added a comment -

          I'm not sure that inlining the schemas is the best solution. I'll hold my comments on trying to mimic what .NET is doing as a good thing Please keep in mind, my solution focuses on statically defined wsdl, not dynamically generated wsdl. In general, static wsdl doesn't seem to be supported nearly as well in spring-ws as is the dynamically generated approach. This is very true when the static wsdl imports schemas and those schemas import other schemas. This is considered a best practice by many in the SOA community as it promotes reuse of types.

          I think that spring-ws will be more successful if it supports static wsdl as well as it does dynamic wsdl. Even though spring-ws doesn't necessarily need the static wsdl in order to function, it should still provide standard ways to access it (via ?wsdl query parm on the url) and standard ways to resolve all location specific elements and attributes embedded within.

          My thoughts are that the static wsdl and associated schema files are essential parts of defining the Web services contract and that they should be preserved in the form that they were created with as few modifications as possible. In our case, we tried to follow best practices by defining types in separate schema files and then import those schemas into the statically defined wsdl and other schemas. This leads to better reusability of types. The only modification to the wsdl and xsd my solution provided was to resolve the location specific aspects, mostly URL's. Inlining creates one big huge unreadable, unmaintainable wsdl in our case. If I were to look at that from an outsiders point of view, I would come to the conclusion that the wsdl designer didn't know what he was doing. Popular tools like SoapUI can easily pull in all of the schemas using my solution, it just walks through the wsdl and gathers all of the nested schemas (and schemas that import other schemas), pretty standard stuff.

          So while inlining the schemas is functionally equivalent to importing them, it's not very good at all from a design standpoint. You're obviously free to do what you want since spring-ws is your framework but for now we are going to have to keep our modifications in place in order to use spring-ws in a way that is more natural to us (and most likely others). I would like to see these modificiations be included in spring-ws so that others may benefit but that's kind of up to you. FWIW, Weblogic provides similiar functionality in regards to static wsdl and nested schemas.

          The other thing I'd like to point out is that most projects of any size will most likely have separate .jars for their XMLBeans (or equivalent XML to Java binding) classes. In our case, we did not want to have to drop the .xsd into both the XMLBeans maven project AND the .war project. Instead, it was fairly easy to simply make a classpath reference in the spring config for the schemas.

          Show
          lafondoo Mark LaFond added a comment - I'm not sure that inlining the schemas is the best solution. I'll hold my comments on trying to mimic what .NET is doing as a good thing Please keep in mind, my solution focuses on statically defined wsdl, not dynamically generated wsdl. In general, static wsdl doesn't seem to be supported nearly as well in spring-ws as is the dynamically generated approach. This is very true when the static wsdl imports schemas and those schemas import other schemas. This is considered a best practice by many in the SOA community as it promotes reuse of types. I think that spring-ws will be more successful if it supports static wsdl as well as it does dynamic wsdl. Even though spring-ws doesn't necessarily need the static wsdl in order to function, it should still provide standard ways to access it (via ?wsdl query parm on the url) and standard ways to resolve all location specific elements and attributes embedded within. My thoughts are that the static wsdl and associated schema files are essential parts of defining the Web services contract and that they should be preserved in the form that they were created with as few modifications as possible. In our case, we tried to follow best practices by defining types in separate schema files and then import those schemas into the statically defined wsdl and other schemas. This leads to better reusability of types. The only modification to the wsdl and xsd my solution provided was to resolve the location specific aspects, mostly URL's. Inlining creates one big huge unreadable, unmaintainable wsdl in our case. If I were to look at that from an outsiders point of view, I would come to the conclusion that the wsdl designer didn't know what he was doing. Popular tools like SoapUI can easily pull in all of the schemas using my solution, it just walks through the wsdl and gathers all of the nested schemas (and schemas that import other schemas), pretty standard stuff. So while inlining the schemas is functionally equivalent to importing them, it's not very good at all from a design standpoint. You're obviously free to do what you want since spring-ws is your framework but for now we are going to have to keep our modifications in place in order to use spring-ws in a way that is more natural to us (and most likely others). I would like to see these modificiations be included in spring-ws so that others may benefit but that's kind of up to you. FWIW, Weblogic provides similiar functionality in regards to static wsdl and nested schemas. The other thing I'd like to point out is that most projects of any size will most likely have separate .jars for their XMLBeans (or equivalent XML to Java binding) classes. In our case, we did not want to have to drop the .xsd into both the XMLBeans maven project AND the .war project. Instead, it was fairly easy to simply make a classpath reference in the spring config for the schemas.
          Hide
          lafondoo Mark LaFond added a comment -

          Or, if you want to allow the user to decide how they want to view it you could add a query parm on the URL such as:

          • ?wsdl&inline=true
          • ?Order.xsd&inline=true

          That's probably a little more flexible that hardwiring it into the spring config.

          Show
          lafondoo Mark LaFond added a comment - Or, if you want to allow the user to decide how they want to view it you could add a query parm on the URL such as: ?wsdl&inline=true ?Order.xsd&inline=true That's probably a little more flexible that hardwiring it into the spring config.
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Ok, I've reopened the issue and will take a look at the other enhancements you made for 1.5 final/ the next RC.

          Show
          arjen.poutsma Arjen Poutsma added a comment - Ok, I've reopened the issue and will take a look at the other enhancements you made for 1.5 final/ the next RC.
          arjen.poutsma Arjen Poutsma made changes -
          Status Closed [ 6 ] Reopened [ 4 ]
          Resolution Fixed [ 1 ]
          Hide
          fbascheper Erik-Berndt Scheper added a comment -

          I second Mark's opinion, that xsd's in a static wsdl generally need not be inlined, but should be made available as is. We are also using complex xsd structures and including / importing them makes allows us to keep each xsd concise and readable.

          Maybe this could be resolved in a similar way as Axis2 supports this, like so:
          *publish the static wsdl as http://some.url/appcontext/services/myservice?wsdl
          including a modified location of each included / imported xsd

          *publish each xsd recursively resolved as
          http://some.url/appcontext/services/myservice?xsd=xsd0
          http://some.url/appcontext/services/myservice?xsd=xsd1
          including a modified location of each included / imported xsd

          • and a startup error in the case a referenced xsd cannot be resolved.
          Show
          fbascheper Erik-Berndt Scheper added a comment - I second Mark's opinion, that xsd's in a static wsdl generally need not be inlined, but should be made available as is. We are also using complex xsd structures and including / importing them makes allows us to keep each xsd concise and readable. Maybe this could be resolved in a similar way as Axis2 supports this, like so: *publish the static wsdl as http://some.url/appcontext/services/myservice?wsdl including a modified location of each included / imported xsd *publish each xsd recursively resolved as http://some.url/appcontext/services/myservice?xsd=xsd0 http://some.url/appcontext/services/myservice?xsd=xsd1 including a modified location of each included / imported xsd and a startup error in the case a referenced xsd cannot be resolved.
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          I think Mark's solution actually works like you said, with the ?xsd queries. The one problem I have is that in Spring-WS, there is no concept of a Service; there are only endpoints. Multiple endpoints can make up a service, of course. So how would you relate one of the potentially many Wsdl11Definition beans to a service? It's relatively easier to relate the XSDs to the WSDL, allowing http://some.url/appcontext/services/myservice?xsd=xsd0, because they are referenced.

          One thing to note is that the current solution only imports and includes XSDs in the WSDL served at runtime. You still have files which you can edit separately, just like you had before. And, as SWS-271 indicates, some clients actually do have issues with included and imported XSDs.

          Show
          arjen.poutsma Arjen Poutsma added a comment - I think Mark's solution actually works like you said, with the ?xsd queries. The one problem I have is that in Spring-WS, there is no concept of a Service; there are only endpoints. Multiple endpoints can make up a service, of course. So how would you relate one of the potentially many Wsdl11Definition beans to a service? It's relatively easier to relate the XSDs to the WSDL, allowing http://some.url/appcontext/services/myservice?xsd=xsd0 , because they are referenced. One thing to note is that the current solution only imports and includes XSDs in the WSDL served at runtime. You still have files which you can edit separately, just like you had before. And, as SWS-271 indicates, some clients actually do have issues with included and imported XSDs.
          arjen.poutsma Arjen Poutsma made changes -
          Fix Version/s 1.5 RC1 [ 10652 ]
          Fix Version/s 1.5 [ 10653 ]
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          I'd really like to put this in 1.5, but I'm seeing some issues, and time is running out. I might have to postpone this to a later release.

          @Mark

          I am looking into the XsdDefinitionHandlerAdapter: is there any particular reason why you used a different algorithm in the transformSchemaLocation() method than the existing one in WsdlDefinitionHandlerAdapter#transformLocation() ?

          I mean, using your example in the readme, can't we just expose Customer.xsd as http://localhost:7001/Services/8.02/Customer.xsd rather than http://localhost:7001/Services/8.02/Example?Customer.xsd ? This seems more consistent with the WSDL approach that we already have.

          @Erik-Berndt
          I am not sure how Axis2' solution works, but I do know that imports/includes get tricky, especially when considering circular references. Using your example: what if http://some.url/appcontext/services/myservice?xsd=xsd0 imported xsd1, which imports xsd0? Where would those schemas be made available?

          I'd rather have more explicit approach, with individual SimpleXsdSchema bean definitions such as Mark proposed, rather than to try to figure out things automagically .

          Show
          arjen.poutsma Arjen Poutsma added a comment - I'd really like to put this in 1.5, but I'm seeing some issues, and time is running out. I might have to postpone this to a later release. @Mark I am looking into the XsdDefinitionHandlerAdapter: is there any particular reason why you used a different algorithm in the transformSchemaLocation() method than the existing one in WsdlDefinitionHandlerAdapter#transformLocation() ? I mean, using your example in the readme, can't we just expose Customer.xsd as http://localhost:7001/Services/8.02/Customer.xsd rather than http://localhost:7001/Services/8.02/Example?Customer.xsd ? This seems more consistent with the WSDL approach that we already have. @Erik-Berndt I am not sure how Axis2' solution works, but I do know that imports/includes get tricky, especially when considering circular references. Using your example: what if http://some.url/appcontext/services/myservice?xsd=xsd0 imported xsd1, which imports xsd0? Where would those schemas be made available? I'd rather have more explicit approach, with individual SimpleXsdSchema bean definitions such as Mark proposed, rather than to try to figure out things automagically .
          Hide
          fbascheper Erik-Berndt Scheper added a comment -

          When I read your comments, I realized that the Axis2 implementation is indeed not appropriate here, because there is no concept of a service but only of endpoints and wsdl definitions. I can think of two solutions that are more in line with the current SimpleWsdl11Definition implementation, which is actually quite nice.

          First of all, the idea is to add an optional property xsdLocator to the SimpleWsdl11Definition, which can be used to link the xsd's to a statically defined wsdl.

          The default implementation of this XsdLocator, let's say the SimpleXsdLocator, should have two properties, xsdLocation and xsdLocations of type Resource and Resource[], so that it is possible to locate multiple xsd's using constructs like 'classpath:/resources/xsd/*/.xsd'

          Then we need a way to publish them so that the xsd's can be loaded from a URL. This could be achieved in two ways:
          1. Add an extra servlet mapping to web.xml (*.xsd) and publish them in a similar way to the SimpleWsdl1Definition already does. But this leads to a complication: the static wsdl and (possibly) xsd's need to be modified so that each xsd can recursively be resolved correctly. The most simple way seems to skip all path prefixes and therefore require each xsd name to be unique.
          This would lead to the following published wsdl and xsd's
          http://some.url/appcontext/myservice.wsdl returning the wsdl definition (resolved by the SimpleWsdl11Definition)
          http://some.url/appcontext/xsdA.xsd returning an xsd (resolved by the SimpleXsdLocator)
          http://some.url/appcontext/xsdB.xsd returning an xsd (resolved by the SimpleXsdLocator)

          2. But if this uniqueness of xsd names is required then it might be much easier to resolve the xsd's using the servlet mapping that is already in place (that of the SimpleWsdl11Definition), and let the SimpleWsdl11Definition publish them instead. This would lead to the following published wsdl and xsd's
          http://some.url/appcontext//myservice.wsdl returning the wsdl definition
          http://some.url/appcontext//myservice.wsdl?xsd=xsdA.xsd returning an xsd resolved using delegation to the SimpleXsdLocator
          http://some.url/appcontext//myservice.wsdl?xsd=xsdB.xsd returning another xsd also resolved by delegating to the SimpleXsdLocator

          The advantage of this alternative is that the user does not need an extra servlet mapping (for *.xsd) and (maybe) that there is a direct link to xsd's used by a specific wsdl.

          Show
          fbascheper Erik-Berndt Scheper added a comment - When I read your comments, I realized that the Axis2 implementation is indeed not appropriate here, because there is no concept of a service but only of endpoints and wsdl definitions. I can think of two solutions that are more in line with the current SimpleWsdl11Definition implementation, which is actually quite nice. First of all, the idea is to add an optional property xsdLocator to the SimpleWsdl11Definition, which can be used to link the xsd's to a statically defined wsdl. The default implementation of this XsdLocator, let's say the SimpleXsdLocator, should have two properties, xsdLocation and xsdLocations of type Resource and Resource[], so that it is possible to locate multiple xsd's using constructs like 'classpath:/resources/xsd/* / .xsd' Then we need a way to publish them so that the xsd's can be loaded from a URL. This could be achieved in two ways: 1. Add an extra servlet mapping to web.xml (*.xsd) and publish them in a similar way to the SimpleWsdl1Definition already does. But this leads to a complication: the static wsdl and (possibly) xsd's need to be modified so that each xsd can recursively be resolved correctly. The most simple way seems to skip all path prefixes and therefore require each xsd name to be unique. This would lead to the following published wsdl and xsd's http://some.url/appcontext/myservice.wsdl returning the wsdl definition (resolved by the SimpleWsdl11Definition) http://some.url/appcontext/xsdA.xsd returning an xsd (resolved by the SimpleXsdLocator) http://some.url/appcontext/xsdB.xsd returning an xsd (resolved by the SimpleXsdLocator) 2. But if this uniqueness of xsd names is required then it might be much easier to resolve the xsd's using the servlet mapping that is already in place (that of the SimpleWsdl11Definition), and let the SimpleWsdl11Definition publish them instead. This would lead to the following published wsdl and xsd's http://some.url/appcontext//myservice.wsdl returning the wsdl definition http://some.url/appcontext//myservice.wsdl?xsd=xsdA.xsd returning an xsd resolved using delegation to the SimpleXsdLocator http://some.url/appcontext//myservice.wsdl?xsd=xsdB.xsd returning another xsd also resolved by delegating to the SimpleXsdLocator The advantage of this alternative is that the user does not need an extra servlet mapping (for *.xsd) and (maybe) that there is a direct link to xsd's used by a specific wsdl.
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Pushing this past 1.5.0 as we need some input from Mark.

          Show
          arjen.poutsma Arjen Poutsma added a comment - Pushing this past 1.5.0 as we need some input from Mark.
          arjen.poutsma Arjen Poutsma made changes -
          Fix Version/s 1.5.1 [ 10917 ]
          Fix Version/s 1.5 [ 10653 ]
          Hide
          ray_harrison Ray Harrison added a comment -

          Hi Arjen,
          We can work for a future release. Mark is buried in getting some releases out and hasn't had much time to devote to this particular item. We will probably always keep our own addition to allow for the ability to use the query parameter for referencing the WSDL. Comcast has a rather large and complex organizational structure and we need to be able to play nicely with how other teams expect to interact with our web services.

          That said, exposing the XSD via the standard Spring-WS as you suggest is perfectly workable from my perspective.

          Thanks,
          Ray

          Show
          ray_harrison Ray Harrison added a comment - Hi Arjen, We can work for a future release. Mark is buried in getting some releases out and hasn't had much time to devote to this particular item. We will probably always keep our own addition to allow for the ability to use the query parameter for referencing the WSDL. Comcast has a rather large and complex organizational structure and we need to be able to play nicely with how other teams expect to interact with our web services. That said, exposing the XSD via the standard Spring-WS as you suggest is perfectly workable from my perspective. Thanks, Ray
          arjen.poutsma Arjen Poutsma made changes -
          Link This issue is superseded by SWS-346 [ SWS-346 ]
          Hide
          arjen.poutsma Arjen Poutsma added a comment -

          Closing this, as the work is at least partially done. I've created a separate issue (SWS-346) for the handler adapter, which you can vote for if you need it.

          Show
          arjen.poutsma Arjen Poutsma added a comment - Closing this, as the work is at least partially done. I've created a separate issue ( SWS-346 ) for the handler adapter, which you can vote for if you need it.
          arjen.poutsma Arjen Poutsma made changes -
          Status Reopened [ 4 ] Closed [ 6 ]
          Resolution Fixed [ 1 ]
          Transition Time In Source Status Execution Times Last Executer Last Execution Date
          Open Open In Progress In Progress
          21d 1h 12m 1 Arjen Poutsma 27/Feb/08 9:31 AM
          In Progress In Progress Resolved Resolved
          9d 20h 35m 1 Arjen Poutsma 08/Mar/08 6:06 AM
          Resolved Resolved Closed Closed
          17h 16m 1 Arjen Poutsma 08/Mar/08 11:23 PM
          Closed Closed Reopened Reopened
          8d 7h 6m 1 Arjen Poutsma 17/Mar/08 6:30 AM
          Reopened Reopened Closed Closed
          45d 14h 39m 1 Arjen Poutsma 01/May/08 9:09 PM

            People

            • Assignee:
              arjen.poutsma Arjen Poutsma
              Reporter:
              lafondoo Mark LaFond
            • Votes:
              8 Vote for this issue
              Watchers:
              11 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: