cxf-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Rastislav Cesnek <...@whitestein.com>
Subject Re: Dynamic service from WSDL+imports loaded from database
Date Fri, 22 Mar 2013 23:04:52 GMT
Thanks for answer Andrei.

I know the cleanest way would be the URL protocol handler (e.g.
"dbresource://whatever). Also due to the fact that a lot of code
everywhere just creates URLs trying to get to a resource and if the
protocol is not valid - bad luck.

However, as there is the ResourceManager component in CXF, it would be
nice if it would be used consistently everywhere.
As it is a nice feature to allow the user to write a custom resource
resolver which can do so based on a string location which does not
necessarily have to be a URL.

I experimented with the following change and it seems to do what I need
(although I did not fully evaluate whether there are potential side
implications). Of course, there is my custom resource resolver
registered with the ResourceManager as I mentioned in previous mail.

In org.apache.cxf.wsdl11.SchemaUtil:

$ svn diff rt/core/src/main/java/org/apache/cxf/wsdl11/SchemaUtil.java
Index: rt/core/src/main/java/org/apache/cxf/wsdl11/SchemaUtil.java
===================================================================
--- rt/core/src/main/java/org/apache/cxf/wsdl11/SchemaUtil.java
(revision 1449715)
+++ rt/core/src/main/java/org/apache/cxf/wsdl11/SchemaUtil.java (working
copy)
@@ -126,8 +126,8 @@
                         String systemId = def.getDocumentBaseURI() +
"#types" + schemaCount;

                         schemaCol.setBaseUri(def.getDocumentBaseURI());
-                        CatalogXmlSchemaURIResolver schemaResolver =
-                            new CatalogXmlSchemaURIResolver(bus);
+                        ResourceManagerXmlSchemaURIResolver
schemaResolver =
+                                       new
ResourceManagerXmlSchemaURIResolver(bus);
                         schemaCol.setSchemaResolver(schemaResolver);

                         XmlSchema xmlSchema =
schemaCol.read(schemaElem, systemId);


And then the quite simple implementation of
ResourceManagerXmlSchemaURIResolver:

package org.apache.cxf.wsdl11;

import java.io.InputStream;
import java.net.URL;
import java.util.Map;

import org.apache.cxf.Bus;
import org.apache.cxf.catalog.CatalogXmlSchemaURIResolver;
import org.apache.cxf.resource.ResourceManager;
import org.apache.ws.commons.schema.resolver.URIResolver;
import org.xml.sax.InputSource;

public class ResourceManagerXmlSchemaURIResolver implements URIResolver {
    private CatalogXmlSchemaURIResolver parent;
    private Bus bus;

    public ResourceManagerXmlSchemaURIResolver(
            CatalogXmlSchemaURIResolver parent, Bus bus) {
        this.parent = parent;
        this.bus = bus;
    }

    public ResourceManagerXmlSchemaURIResolver(Bus bus) {
        this(new CatalogXmlSchemaURIResolver(bus), bus);
    }

    @Override
    public InputSource resolveEntity(String targetNamespace,
            String schemaLocation, String baseUri) {
        InputSource src = getInputSource(schemaLocation);
        if (src == null) {
            src = parent
                    .resolveEntity(targetNamespace, schemaLocation,
baseUri);
        }
        return src;
    }

    private InputSource getInputSource(String schemaLocation) {
        InputStream ins = bus.getExtension(ResourceManager.class)
                .getResourceAsStream(schemaLocation);
        if (ins == null) {
            return null;
        } else {
            InputSource is = new InputSource(ins);
            is.setSystemId(schemaLocation);
            is.setPublicId(schemaLocation);

            URL url =
bus.getExtension(ResourceManager.class).resolveResource(
                    schemaLocation, URL.class);
            if (url != null) {
                is.setSystemId(url.toString());
                is.setPublicId(url.toString());
            }
            return is;
        }
    }

    public Map<? extends String, ? extends String> getResolvedMap() {
        Map<String, String> resolvedMap = parent.getResolvedMap();
        return resolvedMap;
    }

}


On 22. 3. 2013 10:09, Andrei Shakirin wrote:
> Hi Rastislav,
>
> To be honest, I have resolved the similar case only through self-contained WSDL (all
schemas are embedded into WSDL).
> Anyway I find the topic quite interesting. Perhaps Dan can give you some more entry points
to digging.
>
> Regards,
> Andrei.
>
>
>> -----Original Message-----
>> From: Rastislav Cesnek [mailto:rac@whitestein.com]
>> Sent: Dienstag, 19. März 2013 16:16
>> To: users@cxf.apache.org
>> Subject: Dynamic service from WSDL+imports loaded from database
>>
>> HI all.
>>
>> I am trying to tweak CXF into a very dynamic scenario, where services would
>> be published dynamically from a priori unknown WSLDs uploaded at run time
>> (together with an interpreted service implementation).
>>
>> Basically, I already have some idea about the dynamic publish (using custom
>> Invoker and custom DataBinding, etc.).
>>
>> What I concept-proofed right now is loading the WSDLs + its imports from
>> database.
>>
>> Here I stumble upon some show stoppers, when I try to create ServiceInfos
>> from a definition like:
>> WSDLServiceBuilder builder = new WSDLServiceBuilder(bus);
>> List<ServiceInfo> serviceInfos = builder.buildServices(definition);
>>
>> The problem is that I am able to read the Definition while serving the content
>> as I wish (from DB, 2 approaches desribed below), however, the
>> WSDLServiceBuilder fails when it tries to get the schemas (I cannot find a
>> possibility to tweak the resource resolving here, as there is a
>> CatalogXmlSchemaURIResolver hard-registered as schema collection
>> resolver):
>>
>> org.apache.ws.commons.schema.XmlSchemaException: Unable to locate
>> imported document at 'db#RootXSD.xsd', relative to
>> 'db#SubWSDL.wsdl#types1'.
>> at
>> org.apache.cxf.catalog.CatalogXmlSchemaURIResolver.resolveEntity(Catalog
>> XmlSchemaURIResolver.java:76)
>> at
>> org.apache.ws.commons.schema.SchemaBuilder.resolveXmlSchema(Schem
>> aBuilder.java:684)
>> at
>> org.apache.ws.commons.schema.SchemaBuilder.handleImport(SchemaBuild
>> er.java:538)
>> at
>> org.apache.ws.commons.schema.SchemaBuilder.handleSchemaElementChil
>> d(SchemaBuilder.java:1513)
>> at
>> org.apache.ws.commons.schema.SchemaBuilder.handleXmlSchemaElement
>> (SchemaBuilder.java:659)
>> at
>> org.apache.ws.commons.schema.XmlSchemaCollection.read(XmlSchemaColl
>> ection.java:540)
>> at
>> org.apache.cxf.common.xmlschema.SchemaCollection.read(SchemaCollectio
>> n.java:129)
>> at org.apache.cxf.wsdl11.SchemaUtil.extractSchema(SchemaUtil.java:133)
>> at org.apache.cxf.wsdl11.SchemaUtil.getSchemas(SchemaUtil.java:81)
>> at org.apache.cxf.wsdl11.SchemaUtil.getSchemas(SchemaUtil.java:65)
>> at org.apache.cxf.wsdl11.SchemaUtil.getSchemas(SchemaUtil.java:60)
>> at
>> org.apache.cxf.wsdl11.WSDLServiceBuilder.getSchemas(WSDLServiceBuilder
>> .java:372)
>>
>> Any ideas? Can anything like this be done?
>>
>>
>> Basically, for the Definition reading, I tried two approaches which both
>> work:
>>
>> 1) Implementing and registering a CustomResourceResolver with the
>> ResourceManager in the Bus and using standard
>> WSDLManager.getDefinition(String url) method.
>> In the CustomResourceResolver:
>> - in "public InputStream getAsStream(String name)" I recognize the resource
>> name (like "db#name") name and provide na InputSream.
>> - in "public <T> T resolve(String resourceName, Class<T> resourceType)"
>> I always return null (for the URL), so the systemId/publicId of the
>> constructed InputSource stays in the "db#name" form.
>>
>> 2) Copying some code from CXF and implementing custom WSDLLocator and
>> doing completely custom definition reading like:
>> WSDLManager wsdlManager = bus.getExtension(WSDLManager.class);
>> WSDLFactory wsdlFactory = wsdlManager.getWSDLFactory();
>> ExtensionRegistry extensionRegistry = wsdlManager.getExtensionRegistry();
>>
>> WSDLReader reader = wsdlFactory.newWSDLReader();
>> reader.setFeature("javax.wsdl.verbose", false);
>> reader.setFeature("javax.wsdl.importDocuments", true);
>> reader.setExtensionRegistry(extensionRegistry);
>>
>> CatalogWSDLLocator catLocator = new CatalogWSDLLocator(url, bus);
>> CustomDelegatingWSDLLocator = new CustomDelegatingWSDLLocator(url,
>> catLocator, bus); Definition def = reader.readWSDL(wsdlLocator);
>> wsdlManager.addDefinition(url, def); In the CustomDelegatingWSDLLocator I
>> do similar stuff like in the CustomResourceResolver, i.e. provide InputSource
>> or delegate and return an URI (which again stays in the form "db#name" and
>> gets set to
>> systemId/publicId) or delegate.
>>
>> This works charming and the definition is read.
>>
>>
>> I considered using custom URL protocol handler but this is a show-stopper
>> too, as the application runs on JEE server, where I cannot register a custom
>> protocol handler easily (usually, a URLStreamHandlerFactory is already set
>> and it cannot be set a second time). The option to use the system
>> environment property -Djava.protocol.handler.pkgs is also cumbersome as it
>> requires installing classes/modules deep into the server/java core.
>>
>> Please, notice that Whitestein Slovakia has moved to a new location.
>> Prosím, všimnite si že Whitestein Slovensko sa presťahovalo na novú adresu.
>>
>> --
>> Rastislav Cesnek | rac@whitestein.com
>> Senior Software Engineer | Advanced Technologies Whitestein Technologies
>> s.r.o. | www.whitestein.com Moskovska 13 | 811 08 Bratislava-Staré Mesto |
>> Slovak Republic Main +421 2 5443-5502 | Fax +421 2 5443-5512

Please, notice that Whitestein Slovakia has moved to a new location.
Prosím, všimnite si že Whitestein Slovensko sa presťahovalo na novú adresu.

-- 
Rastislav Cesnek | rac@whitestein.com
Senior Software Engineer | Advanced Technologies
Whitestein Technologies s.r.o. | www.whitestein.com
Moskovska 13 | 811 08 Bratislava-Staré Mesto | Slovak Republic
Main +421 2 5443-5502 | Fax +421 2 5443-5512


Mime
View raw message