/* * Copyright 2012 JBoss Inc * * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.artificer.demos.endtoend.impactanalysis; import org.artificer.client.ArtificerAtomApiClient; import org.artificer.common.query.ArtifactSummary; import org.artificer.client.query.QueryResultSet; import org.artificer.common.ArtifactTypeEnum; import org.artificer.common.ArtificerConstants; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.BaseArtifactEnum; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.BaseArtifactType; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.DerivedArtifactEnum; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.DerivedArtifactTarget; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.Organization; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.ServiceEndpoint; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.ServiceImplementationModelEnum; import org.oasis_open.docs.s_ramp.ns.s_ramp_v1.ServiceImplementationModelTarget; import java.io.InputStream; import java.util.Iterator; /** * In this demo, we pretend that we're a part of a large software development company, focused on provided * SOAP-based services. Assume a common schema is used across the board. Reuse is a good thing, right? * * What if I want to update, replace, or create a new version of that schema? What software and what teams will be * impacted? More specifically, what will be impacted if I change a *specific element* of the schema? * * This demo shows the processes and specific queries used in traversing the bi-directional relationship tree, * providing both coarse and fine grained impact analysis for your organization's artifacts. * * @author Brett Meyer */ public class ImpactAnalysisDemo { private static final String DEFAULT_ENDPOINT = "http://localhost:8080/artificer-server"; private static final String DEFAULT_USER = "admin"; private static final String DEFAULT_PASSWORD = "artificer1!"; public static void main(String[] args) throws Exception { System.out.println("\n*** Running Demo ***\n"); String endpoint = System.getProperty("artificer.endpoint"); String username = System.getProperty("artificer.auth.username"); String password = System.getProperty("artificer.auth.password"); if (endpoint == null || endpoint.trim().length() == 0) { endpoint = DEFAULT_ENDPOINT; } if (username == null || username.trim().length() == 0) { username = DEFAULT_USER; } if (password == null || password.trim().length() == 0) { password = DEFAULT_PASSWORD; } System.out.println("Artificer Endpoint: " + endpoint); System.out.println("Artificer User: " + username); ArtificerAtomApiClient client = new ArtificerAtomApiClient(endpoint, username, password, true); System.out.println("\nUploading XSD artifact (sample.xsd)..."); InputStream is = ImpactAnalysisDemo.class.getResourceAsStream("sample.xsd"); BaseArtifactType xsdArtifact = client.uploadArtifact(is, "sample.xsd"); is.close(); System.out.println("Uploading WSDL artifact (sample.wsdl)..."); is = ImpactAnalysisDemo.class.getResourceAsStream("sample.wsdl"); BaseArtifactType wsdlArtifact = client.uploadArtifact(is, "sample.wsdl"); is.close(); System.out.println("\nTake a look at the primary artifacts, derived artifacts, and relationships through the UI: " + "http://[HOST]:[PORT]/artificer-ui/index.html"); System.out.println("\nRetrieving a specific type declaration (needed later), which was derived from the XSD..."); String query = String.format("/s-ramp/xsd/ComplexTypeDeclaration[@name='%s']", "outputType"); System.out.println("*** Query: " + query); QueryResultSet resultSet = client.query(query); ArtifactSummary typeSummary = resultSet.iterator().next(); System.out.println("ComplexTypeDeclaration: " + typeSummary.getName()); System.out.println("\nRetrieving the Service artifact (needed later), which was derived from the WSDL..."); query = String.format("/s-ramp/wsdl/WsdlService[relatedDocument[@uuid='%s']]", wsdlArtifact.getUuid()); System.out.println("*** Query: " + query); resultSet = client.query(query); ArtifactSummary serviceSummary = resultSet.iterator().next(); System.out.println("Service: " + serviceSummary.getName()); System.out.println("\nShowing that the WSDL imported the XSD and a relationship is defined..."); query = String.format("/s-ramp/wsdl/WsdlDocument[@uuid = '%s']/importedXsds", wsdlArtifact.getUuid()); System.out.println("*** Query: " + query); resultSet = client.query(query); Iterator<ArtifactSummary> itr = resultSet.iterator(); while (itr.hasNext()) { ArtifactSummary resultSummary = itr.next(); System.out.println("*** Result: " + wsdlArtifact.getName() + " imports " + resultSummary.getName()); } System.out.println("\nShowing all artifact relationships that target the given XSD (should include the 'importedXsds' from the WSDL)..."); System.out.println("NOTE: This is an Artificer-specific endpoint, outside of the S-RAMP spec, allowing reverse/bi-directional traversal!"); System.out.println(String.format("*** Endpoint: /artificer-server/artificer/reverseRelationships/%s", xsdArtifact.getUuid())); resultSet = client.reverseRelationships(xsdArtifact.getUuid()); itr = resultSet.iterator(); while (itr.hasNext()) { ArtifactSummary resultSummary = itr.next(); // The /reverseRelationships endpoint includes the relationship type name as an extension attribute on the results! String relationshipType = (String) resultSummary.getExtensionAttribute( ArtificerConstants.ARTIFICER_RELATIONSHIP_TYPE_QNAME); System.out.println("*** Result: " + resultSummary.getName() + " --> '" + relationshipType + "' --> " + xsdArtifact.getName()); } System.out.println("\nCreating SOA & ServiceImplementation logical artifacts:"); System.out.println("Creating ServiceEndpoint 'ABC', which has a 'definedBy' relationship to the WSDL service..."); ServiceEndpoint serviceEndpointArtifact = new ServiceEndpoint(); serviceEndpointArtifact.setArtifactType(BaseArtifactEnum.SERVICE_ENDPOINT); serviceEndpointArtifact.setName("Service Endpoint ABC"); DerivedArtifactTarget serviceTarget = new DerivedArtifactTarget(); serviceTarget.setArtifactType(DerivedArtifactEnum.WSDL_SERVICE); serviceTarget.setValue(serviceSummary.getUuid()); serviceEndpointArtifact.setEndpointDefinedBy(serviceTarget); serviceEndpointArtifact = (ServiceEndpoint) client.createArtifact(serviceEndpointArtifact); System.out.println("Creating Organization 'Team XYZ', which has a 'provides' relationship to the ServiceEndpoint..."); Organization organizationArtifact = new Organization(); organizationArtifact.setArtifactType(BaseArtifactEnum.ORGANIZATION); organizationArtifact.setName("Team XYZ"); ServiceImplementationModelTarget serviceEndpointTarget = new ServiceImplementationModelTarget(); serviceEndpointTarget.setArtifactType(ServiceImplementationModelEnum.SERVICE_ENDPOINT); serviceEndpointTarget.setValue(serviceEndpointArtifact.getUuid()); organizationArtifact.getProvides().add(serviceEndpointTarget); client.createArtifact(organizationArtifact); System.out.println("\nOk, I want to update the content of the schema. But how do I know who/what that impacts?"); System.out.println("Traverse the chain of relationships, starting at the XSD, to find out which organization to contact about the change!"); System.out.println("NOTE: This is easily done in the UI (see link, above). Click on the schema, then on its 'Relationships' tab, to start."); System.out.println("\nFind, once again, all artifacts targeting the XSD with a relationship..."); String nextUuid = reverseRelationship(xsdArtifact.getUuid(), "importedXsds", client); System.out.println("\nOk, looks like a WSDL is importing it. Find all relationships targeting that WSDL... "); resultSet = client.reverseRelationships(nextUuid); itr = resultSet.iterator(); while (itr.hasNext()) { ArtifactSummary resultSummary = itr.next(); String relationshipType = (String) resultSummary.getExtensionAttribute( ArtificerConstants.ARTIFICER_RELATIONSHIP_TYPE_QNAME); System.out.println("*** Result: '" + relationshipType + "' <-- " + resultSummary.getName() + " (" + resultSummary.getType() + ")"); if (resultSummary.getType().equals(ArtifactTypeEnum.WsdlService.getType())) { // Found the service nextUuid = resultSummary.getUuid(); } } System.out.println("\nWow, there's a lot to that WSDL. It looks like it defines a specific service, 'SampleService'. Let's check that out next."); nextUuid = reverseRelationship(nextUuid, "endpointDefinedBy", client); System.out.println("\nLooks like 'Service Endpoint ABC' is defined by that WSDL service. Who is responsible for the endpoint?"); reverseRelationship(nextUuid, null, client); System.out.println("\nAlright, so 'Team XYZ' is responsible for 'Service Endpoint ABC'."); System.out.println("Better contact them and let them know why things are about to break..."); System.out.println("\nMore specifically, I only want to change one single type declaration: 'outputType'."); System.out.println("Within *all* WSDLs in the repo, what exactly is using that type? Again, look at the relationships targeting it."); nextUuid = reverseRelationship(typeSummary.getUuid(), "type", client); System.out.println("Ok, one Part. Keep going. Which Message?"); nextUuid = reverseRelationship(nextUuid, "part", client); System.out.println("Found the Message. Now where is it used?"); nextUuid = reverseRelationship(nextUuid, "message", client); System.out.println("An OperationOutput. Which Operation?"); reverseRelationship(nextUuid, null, client); System.out.println("\nNow I know exactly which pieces of the WSDL will be affected!"); System.out.println("\nOk, ok, I get it. Artificer is pretty sweet..."); System.out.println("\n*** Demo Completed ***\n\n"); } private static String reverseRelationship(String uuid, String desiredRelationshipType, ArtificerAtomApiClient client) throws Exception { QueryResultSet resultSet = client.reverseRelationships(uuid); Iterator<ArtifactSummary> itr = resultSet.iterator(); while (itr.hasNext()) { ArtifactSummary resultSummary = itr.next(); String relationshipType = (String) resultSummary.getExtensionAttribute( ArtificerConstants.ARTIFICER_RELATIONSHIP_TYPE_QNAME); System.out.println("*** Result: '" + relationshipType + "' <-- " + resultSummary.getName() + " (" + resultSummary.getType() + ")"); if (desiredRelationshipType != null && desiredRelationshipType.equals(relationshipType)) { return resultSummary.getUuid(); } } return null; } }