For this scenario, we pretend that we're a part of a large software development company, focused on providing SOA web services. This company attempts to reuse artifacts as much as possible, reducing redundancy and increasing consistency. Reuse is a good thing, right? What if I, a member of a development team within the company, want to update, replace, or create a new version of that schema? What services and what teams will be impacted? Even more specifically, what will be impacted if I change a single type in the schema?
This is where Artificer starts to shine. Further, this need was one of the main use cases driving the original OASIS S-RAMP specification.
In this example, assume we have two primary artifacts:
- sample.xsd: A common schema used throughout the organization.
- sample.wsdl: A specific WSDL controlled and implemented by another team in the organization. Imports sample.xsd and utilizes its types.
When the XSD is uploaded to Artificer, the following artifacts are created:
- sample.xsd (XsdDocument): The "primary" artifact
- extInputType (ComplexTypeDeclaration): A "derived" artifact, representing a complex type declaration
- extOutputType (ComplexTypeDeclaration): A "derived" artifact, representing a complex type declaration
- extInput (ElementDeclaration): A "derived" artifact, representing an element declaration
Uploading the WSDL results in numerous artifacts. I'm summarizing, for the sake of brevity:
- sample.wsdl (WsdlDocument): The "primary" artifact
Artificer automatically recognizes that the WSDL imports the XSD and utilizes its types. When that's the case, several useful "relationships" are automatically created. Note that these relationships are bi-directional! Traversing the tree, up and down, is supported by Artificer.
- All derived artifacts are automatically linked to the primary/parent artifact through a "relatedDocument" relationship. Ex: extOutputType -> "relatedDocument" -> XSD
- WSDL -> "importedXsds" -> XSD
- WSDL Part -> "type" -> XSD ComplexTypeDeclaration
- WSDL Part -> "element" XSD Element
It's important to note that relationships can be defined between primary and derived artifacts! The fine granularity differentiates Artificer and the S-RAMP spec from other alternatives. Through this, full-blown impact analysis becomes possible.
The XSD and WSDL spaces only get us so far. We still need additional metadata to link and describe the artifacts in other useful ways. This is where S-RAMP's "ServiceImplementation" and "SOA" models come into play. The models define dozens of logical, metadata-only artifacts, based on The Open Group SOA Ontology. See the S-RAMP spec's Modeling SOA Concepts section for more info. As a really simple example, here are a few that could be used for for our scenario:
- Organization: Describes a specific organization or team ("actor") within the company
- ServiceEndpoint: Describes a specific SOA endpoint
In this case, a few relationships would be helpful to at least know 1.) what services are in production, 2.) what services utilize given artifacts, and 3.) who is responsible for the services.
- Organization -> "provides" -> ServiceEndpoint
- ServiceEndpoint -> "definedBy" -> WSDL
Note that we're barely scratching the surface of the SOA and ServiceImplementation models -- there is a lot available in both. However, all of the above information is enough to at least give an idea of what's possible.
The following demo code shows the above data model, example processes, and specific queries used to traverse the bi-directional relationship tree. Feel free to use it as a basic template for coarse and fine grained impact analysis within your organization's artifacts! Note that, although this specific demo uses the Java client, the concepts are possible in any Artificer interface! https://github.com/ArtificerRepo/artificer/tree/master/demos/end-to-end-use-case/xsd-wsdl-impact-analysis
Running that demo results in the output, below. Although it's a bit verbose, it attempts to adequately describe the actions.
*** Running Demo ***
Artificer Endpoint: http://localhost:8080/artificer-server
Artificer User: admin
Uploading XSD artifact (sample.xsd)...
Uploading WSDL artifact (sample.wsdl...)
Take a look at the primary artifacts, derived artifacts, and relationships through the UI: http://[HOST]:[PORT]/artificer-ui/index.html
Retrieving a specific type declaration (needed later), which was derived from the XSD...
*** Query: /s-ramp/xsd/ComplexTypeDeclaration[@name='extOutputType']
Retrieving the Service artifact (needed later), which was derived from the WSDL...
*** Query: /s-ramp/wsdl/WsdlService[relatedDocument[@uuid='60a87a04-502c-4962-b8fd-6bea7bcfcbca']]
Showing that the WSDL imported the XSD and a relationship is defined...
*** Query: /s-ramp/wsdl/WsdlDocument[@uuid = '60a87a04-502c-4962-b8fd-6bea7bcfcbca']/importedXsds
*** Result: sample.wsdl imports sample.xsd
Showing all artifact relationships that target the given XSD (should include the 'importedXsds' from the WSDL)...
NOTE: This is an Artificer-specific endpoint, outside of the S-RAMP spec, allowing reverse/bi-directional traversal!
*** Endpoint: /artificer-server/artificer/reverseRelationships/d0abaf7e-1ff5-4151-ad0d-df230704d9e5
*** Result: sample.wsdl --> 'importedXsds' --> sample.xsd
*** Result: extOutputType --> 'relatedDocument' --> sample.xsd
*** Result: extInput --> 'relatedDocument' --> sample.xsd
*** Result: extInputType --> 'relatedDocument' --> sample.xsd
Creating SOA & ServiceImplementation logical artifacts:
Creating ServiceEndpoint 'ABC', which has a 'definedBy' relationship to the WSDL service...
Creating Organization 'Team XYZ', which has a 'provides' relationship to the ServiceEndpoint...
Ok, I want to update the content of the schema. But how do I know who/what that impacts?
Traverse the chain of relationships, starting at the XSD, to find out which organization to contact about the change!
NOTE: This is easily done in the UI (see link, above). Click on the schema, then on its 'Relationships' tab, to start.
Find, once again, all artifacts targeting the XSD with a relationship...
*** Result: 'importedXsds' <-- sample.wsdl (WsdlDocument)
*** Result: 'relatedDocument' <-- extOutputType (ComplexTypeDeclaration)
*** Result: 'relatedDocument' <-- extInput (ElementDeclaration)
*** Result: 'relatedDocument' <-- extInputType (ComplexTypeDeclaration)
Ok, looks like a WSDL is importing it. Find all relationships targeting that WSDL...
*** Result: 'relatedDocument' <-- soap:binding (SoapBinding)
*** Result: 'relatedDocument' <-- SampleBinding (Binding)
*** Result: 'relatedDocument' <-- errorFault (BindingOperationFault)
*** Result: 'relatedDocument' <-- findRequest (OperationInput)
*** Result: 'relatedDocument' <-- parameters (Part)
*** Result: 'relatedDocument' <-- findResponse (Message)
*** Result: 'relatedDocument' <-- findResponse (OperationOutput)
*** Result: 'relatedDocument' <-- emptyMessage (Message)
*** Result: 'relatedDocument' <-- parameters (Part)
*** Result: 'relatedDocument' <-- findRequest (Message)
*** Result: 'relatedDocument' <-- SampleService (WsdlService)
*** Result: 'relatedDocument' <-- find (BindingOperation)
*** Result: 'relatedDocument' <-- errorFault (Fault)
*** Result: 'relatedDocument' <-- find (Operation)
*** Result: 'relatedDocument' <-- SamplePort (Port)
*** Result: 'relatedDocument' <-- unknownFault (BindingOperationFault)
*** Result: 'relatedDocument' <-- SamplePortType (PortType)
*** Result: 'relatedDocument' <-- findResponse (BindingOperationOutput)
*** Result: 'relatedDocument' <-- soap:address (SoapAddress)
*** Result: 'relatedDocument' <-- findRequest (BindingOperationInput)
*** Result: 'relatedDocument' <-- message (Part)
*** Result: 'relatedDocument' <-- unknownFault (Fault)
*** Result: 'relatedDocument' <-- faultMessage (Message)
Wow, there's a lot to that WSDL. It looks like it defines a specific service. Let's check that out next.
*** Result: 'endpointDefinedBy' <-- Service Endpoint ABC (ServiceEndpoint)
Looks like 'Service Endpoint ABC' is defined by that WSDL service. Who is responsible for the endpoint?
*** Result: 'provides' <-- Team XYZ (Organization)
Alright, so 'Team XYZ' is responsible for 'Service Endpoint ABC'.
Better contact them and let them know why things are about to break...
More specifically, I only want to change one single type declaration: 'extOutputType'.
Within *all* WSDLs in the repo, what exactly is using that type? Again, look at the relationships targeting it.
*** Result: 'type' <-- parameters (Part)
Ok, one Part. Keep going. Which Message?
*** Result: 'part' <-- findResponse (Message)
Found the Message. Now where is it used?
*** Result: 'message' <-- findResponse (OperationOutput)
An OperationOutput. Which Operation?
*** Result: 'output' <-- find (Operation)
Now I know exactly which pieces of the WSDL will be affected!
Ok, ok, I get it. Artificer is pretty sweet...
*** Demo Completed ***