├── .github
├── CODEOWNERS
├── workflows
│ ├── pull_request_ubuntu_build.yml
│ └── push_ubuntu_build.yml
└── ISSUE_TEMPLATE
│ ├── task.yml
│ ├── config.yml
│ ├── improvement.yml
│ ├── new-feature.yml
│ └── bug.yml
├── src
├── test
│ ├── resources
│ │ ├── complex
│ │ │ ├── arrayMessage.json
│ │ │ ├── nestedMessage.json
│ │ │ ├── choice.xsd
│ │ │ ├── groups.xsd
│ │ │ ├── arrays.xsd
│ │ │ ├── arrays.wsdl
│ │ │ ├── choice.wsdl
│ │ │ ├── groups.wsdl
│ │ │ ├── invalid.wsdl
│ │ │ ├── nested.wsdl
│ │ │ └── nested.xsd
│ │ ├── calculator
│ │ │ ├── calculator.xsd
│ │ │ └── calculator.wsdl
│ │ ├── calculator-remote
│ │ │ ├── calculator.xsd
│ │ │ └── calculator.wsdl
│ │ └── issue-28
│ │ │ └── failing.wsdl
│ └── java
│ │ └── org
│ │ └── wso2
│ │ └── soaptorest
│ │ ├── utils
│ │ └── ListJSONPathsTest.java
│ │ ├── WSDLExceptionTest.java
│ │ ├── SOAPToRESTConverterTest.java
│ │ └── ComplexWSDLTestCase.java
└── main
│ └── java
│ └── org
│ └── wso2
│ └── soaptorest
│ ├── exceptions
│ └── SOAPToRESTException.java
│ ├── models
│ ├── WSDLParameter.java
│ ├── XSSequence.java
│ ├── XSAttribute.java
│ ├── XSChoice.java
│ ├── SOAPRequestElement.java
│ ├── XSGroup.java
│ ├── XSElement.java
│ ├── SOAPtoRESTConversionData.java
│ ├── XSDataType.java
│ ├── XSModel.java
│ ├── WSDLInfo.java
│ └── WSDLSOAPOperation.java
│ ├── SOAPToRESTConverter.java
│ ├── utils
│ ├── SOAPToRESTConstants.java
│ ├── ListJSONPaths.java
│ ├── WSDLProcessingUtil.java
│ └── SOAPOperationExtractingUtil.java
│ ├── WSDLProcessor.java
│ ├── OASGenerator.java
│ └── SOAPRequestBodyGenerator.java
├── .gitignore
├── limitations.md
├── pull_request_template.md
├── README.md
├── pom.xml
└── LICENSE
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Lines starting with '#' are comments.
2 | # Each line is a file pattern followed by one or more owners.
3 |
4 | # See: https://help.github.com/articles/about-codeowners/
5 |
6 | # These owners will be the default owners for everything in the repo.
7 | * @rosensilva
8 |
--------------------------------------------------------------------------------
/src/test/resources/complex/arrayMessage.json:
--------------------------------------------------------------------------------
1 | {
2 | "inputModel": {
3 | "inner1": {
4 | "inner2": {
5 | "inner3": {
6 | "intA": 0,
7 | "intB": 0
8 | },
9 | "int3": 0
10 | },
11 | "int2": 0
12 | },
13 | "int1": 0
14 | }
15 | }
--------------------------------------------------------------------------------
/src/test/resources/complex/nestedMessage.json:
--------------------------------------------------------------------------------
1 | {
2 | "inputModel": {
3 | "inner1": {
4 | "inner2": {
5 | "inner3": {
6 | "intA": 0,
7 | "intB": 0
8 | },
9 | "int3": 0
10 | },
11 | "int2": 0
12 | },
13 | "int1": 0
14 | }
15 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 | .idea/
25 | .classpath
26 | .project
27 | .settings/
28 | /target/
29 |
--------------------------------------------------------------------------------
/.github/workflows/pull_request_ubuntu_build.yml:
--------------------------------------------------------------------------------
1 | name: CI - Pull request - Ubuntu
2 |
3 | on:
4 | pull_request:
5 | branches: [ "main" ]
6 |
7 | jobs:
8 | build:
9 |
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Set up JDK 11
15 | uses: actions/setup-java@v4
16 | with:
17 | java-version: '11'
18 | distribution: 'temurin'
19 | cache: maven
20 | - name: Build with Maven
21 | run: mvn clean install
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/task.yml:
--------------------------------------------------------------------------------
1 | name: "✍️ Create a Task"
2 | description: Create a new task.
3 | labels: ["Type/Task"]
4 | body:
5 | - type: textarea
6 | id: description
7 | attributes:
8 | label: Description
9 | description: A clear description of what needs to be done.
10 | validations:
11 | required: true
12 | - type: input
13 | id: version
14 | attributes:
15 | label: Version
16 | description: Enter product/component version.
17 | validations:
18 | required: false
19 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: '📚 Documentation Issue'
4 | about: Request a new article, missing topic, or report an issue if a topic is incorrect in the current documentation.
5 | url: https://github.com/wso2/docs-mi/issues/new/choose
6 | - name: General Question
7 | url: https://stackoverflow.com/questions/tagged/wso2-micro-integrator
8 | about: "If you have a question then please ask on Stack Overflow using the #wso2-micro-integrator tag."
9 | - name: Chat on help-micro-integrator Discord Channel
10 | url: https://discord.com/invite/Xa5VubmThw
11 | about: "Chat about anything else with the community."
12 |
--------------------------------------------------------------------------------
/.github/workflows/push_ubuntu_build.yml:
--------------------------------------------------------------------------------
1 | name: CI - Push request - Ubuntu
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 |
7 | jobs:
8 | build:
9 |
10 | runs-on: ubuntu-latest
11 |
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Set up JDK 11
15 | uses: actions/setup-java@v4
16 | with:
17 | java-version: '11'
18 | distribution: 'temurin'
19 | cache: maven
20 | - name: Build with Maven
21 | run: mvn clean install
22 | - name: Upload test coverage to Codecov
23 | uses: codecov/codecov-action@v4.0.1
24 | with:
25 | flags: unit_tests
26 | token: ${{ secrets.CODECOV_TOKEN }}
27 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/improvement.yml:
--------------------------------------------------------------------------------
1 | name: "🚀 Improvement Request"
2 | description: Suggest an improvement to the product.
3 | labels: ["Type/Improvement"]
4 | body:
5 | - type: textarea
6 | id: limitation
7 | attributes:
8 | label: Current Limitation
9 | description: Describe the the current limitation.
10 | validations:
11 | required: true
12 | - type: textarea
13 | id: suggestion
14 | attributes:
15 | label: Suggested Improvement
16 | description: Describe the the improvement you suggest.
17 | validations:
18 | required: true
19 | - type: input
20 | id: version
21 | attributes:
22 | label: Version
23 | description: Enter component version.
24 | validations:
25 | required: false
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/new-feature.yml:
--------------------------------------------------------------------------------
1 | name: "💡 New Feature Request"
2 | description: Suggest new functionality and features for the product.
3 | labels: ["Type/NewFeature"]
4 | body:
5 | - type: textarea
6 | id: problem
7 | attributes:
8 | label: Problem
9 | description: What is the problem this feature will solve?
10 | validations:
11 | required: true
12 | - type: textarea
13 | id: solution
14 | attributes:
15 | label: Proposed Solution
16 | description: Describe the solution you'd like to have.
17 | validations:
18 | required: true
19 | - type: textarea
20 | id: alternatives
21 | attributes:
22 | label: Alternatives
23 | description: Describe any alternatives have you considered
24 | validations:
25 | required: false
26 | - type: input
27 | id: version
28 | attributes:
29 | label: Version
30 | description: Enter product/component version.
31 | validations:
32 | required: false
33 |
--------------------------------------------------------------------------------
/src/test/resources/complex/choice.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.yml:
--------------------------------------------------------------------------------
1 | name: "🐞 Report a Bug"
2 | description: Create an issue if something does not work as expected.
3 | labels: ["Type/Bug"]
4 | body:
5 | - type: textarea
6 | id: background
7 | attributes:
8 | label: Description
9 | description: Please share a clear and concise description of the problem.
10 | placeholder: Description
11 | - type: textarea
12 | id: steps
13 | attributes:
14 | label: Steps to Reproduce
15 | description: List the steps you followed when you encountered the issue. Provide sample source code to reproduce the issue where applicable.
16 | validations:
17 | required: true
18 | - type: input
19 | id: version
20 | attributes:
21 | label: Version
22 | description: Enter product/component version.
23 | validations:
24 | required: true
25 | - type: textarea
26 | id: environment
27 | attributes:
28 | label: Environment Details (with versions)
29 | description: Mention the environment details (OS, Client, etc.) that the product is running on.
30 | validations:
31 | required: false
32 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/exceptions/SOAPToRESTException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.exceptions;
19 |
20 | /**
21 | * Custom exception class to be thrown when an issue encountered in SOAP to REST Conversion.
22 | */
23 | public class SOAPToRESTException extends Exception {
24 |
25 | public SOAPToRESTException(String msg, Throwable e) {
26 |
27 | super(msg, e);
28 | }
29 |
30 | public SOAPToRESTException(String msg) {
31 |
32 | super(msg);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/WSDLParameter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import javax.xml.namespace.QName;
21 |
22 | public class WSDLParameter {
23 |
24 | private final QName qName;
25 | private final MessageType messageType;
26 |
27 | public WSDLParameter(QName qName, MessageType messageType) {
28 |
29 | this.qName = qName;
30 | this.messageType = messageType;
31 | }
32 |
33 | public QName getQName() {
34 |
35 | return qName;
36 | }
37 |
38 | public MessageType getMessageType() {
39 |
40 | return messageType;
41 | }
42 |
43 | public enum MessageType {
44 |
45 | ELEMENT, TYPE
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSSequence.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * Model for represent Sequence element in the given XSD
25 | */
26 | public class XSSequence {
27 |
28 | List elementList = new ArrayList<>();
29 | List sequenceList = new ArrayList<>();
30 | List choiceList = new ArrayList<>();
31 |
32 | public List getElementList() {
33 |
34 | return elementList;
35 | }
36 |
37 | public void addElement(XSElement element) {
38 |
39 | elementList.add(element);
40 | }
41 |
42 | public List getSequenceList() {
43 |
44 | return sequenceList;
45 | }
46 |
47 | public List getChoiceList() {
48 |
49 | return choiceList;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/resources/complex/groups.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSAttribute.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import javax.xml.namespace.QName;
21 |
22 | /**
23 | * Model for represent Attribute in the given XSD
24 | */
25 | public class XSAttribute {
26 |
27 | QName name;
28 | QName type;
29 | QName refKey;
30 | XSDataType inlineComplexType;
31 |
32 | public QName getName() {
33 |
34 | return name;
35 | }
36 |
37 | public void setName(QName name) {
38 |
39 | this.name = name;
40 | }
41 |
42 | public QName getType() {
43 |
44 | return type;
45 | }
46 |
47 | public void setType(QName type) {
48 |
49 | this.type = type;
50 | }
51 |
52 | public void setInlineComplexType(XSDataType inlineComplexType) {
53 |
54 | this.inlineComplexType = inlineComplexType;
55 | }
56 |
57 | public void setRefKey(QName refKey) {
58 |
59 | this.refKey = refKey;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/test/resources/complex/arrays.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSChoice.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * Model for represent Choice element in the given XSD
25 | */
26 | public class XSChoice {
27 |
28 | List sequenceList = new ArrayList<>();
29 | List choiceList = new ArrayList<>();
30 | List groupsList = new ArrayList<>();
31 | List elementList = new ArrayList<>();
32 |
33 | public List getSequenceList() {
34 |
35 | return sequenceList;
36 | }
37 |
38 | public List getChoiceList() {
39 |
40 | return choiceList;
41 | }
42 |
43 | public List getGroupsList() {
44 |
45 | return groupsList;
46 | }
47 |
48 | public List getElementList() {
49 |
50 | return elementList;
51 | }
52 |
53 | public void addElement(XSElement element) {
54 |
55 | elementList.add(element);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/SOAPRequestElement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import org.w3c.dom.Document;
21 |
22 | /**
23 | * Data model for a single soap request.
24 | */
25 | public class SOAPRequestElement {
26 |
27 | private final Document soapRequestBody;
28 | private final String soapAction;
29 | private final String soapNamespace;
30 | private final String nameSpace;
31 |
32 | public SOAPRequestElement(Document soapRequestBody, String soapAction, String namespace, String soapNamespace) {
33 |
34 | this.soapRequestBody = soapRequestBody;
35 | this.soapAction = soapAction;
36 | this.nameSpace = namespace;
37 | this.soapNamespace = soapNamespace;
38 | }
39 |
40 | public Document getSoapRequestBody() {
41 |
42 | return soapRequestBody;
43 | }
44 |
45 | public String getSoapAction() {
46 |
47 | return soapAction;
48 | }
49 |
50 | public String getSoapNamespace() {
51 |
52 | return soapNamespace;
53 | }
54 |
55 | public String getNamespace() {
56 |
57 | return nameSpace;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import javax.xml.namespace.QName;
21 | import java.util.ArrayList;
22 | import java.util.List;
23 |
24 | /**
25 | * Model for represent Group element in the given XSD
26 | */
27 | public class XSGroup {
28 |
29 | QName refKey;
30 | QName name;
31 | List sequenceList = new ArrayList<>();
32 | List choiceList = new ArrayList<>();
33 |
34 | public List getSequenceList() {
35 |
36 | return sequenceList;
37 | }
38 |
39 | public void addSequence(XSSequence sequence) {
40 |
41 | sequenceList.add(sequence);
42 | }
43 |
44 | public List getChoiceList() {
45 |
46 | return choiceList;
47 | }
48 |
49 | public QName getRefKey() {
50 |
51 | return refKey;
52 | }
53 |
54 | public void setRefKey(QName refKey) {
55 |
56 | this.refKey = refKey;
57 | }
58 |
59 | public QName getName() {
60 | return name;
61 | }
62 |
63 | public void setName(QName name) {
64 | this.name = name;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/org/wso2/soaptorest/utils/ListJSONPathsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.utils;
19 |
20 | import org.apache.commons.io.IOUtils;
21 | import org.junit.jupiter.api.Test;
22 |
23 | import java.io.FileInputStream;
24 | import java.io.IOException;
25 | import java.nio.charset.StandardCharsets;
26 | import java.util.ArrayList;
27 | import java.util.Arrays;
28 |
29 | import static org.junit.jupiter.api.Assertions.assertTrue;
30 |
31 | class ListJSONPathsTest {
32 |
33 | @Test
34 | void getJsonPaths() throws IOException {
35 | ArrayList expectedJSONPaths = new ArrayList<>(Arrays.asList("inputModel.int1", "inputModel.inner1.inner2.inner3.intB",
36 | "inputModel.inner1.inner2.inner3.intA", "inputModel.inner1.inner2.int3", "inputModel.inner1.int2"));
37 |
38 | try (FileInputStream inputStream = new FileInputStream("src/test/resources/complex/nestedMessage.json")) {
39 | String jsonString = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
40 | ArrayList jsonPaths = ListJSONPaths.getJsonPaths(jsonString);
41 | assertTrue(jsonPaths.containsAll(expectedJSONPaths) && expectedJSONPaths.containsAll(jsonPaths));
42 | }
43 |
44 | }
45 | }
--------------------------------------------------------------------------------
/limitations.md:
--------------------------------------------------------------------------------
1 | # Limitations of SOAP to REST Feature
2 |
3 | ## XSD Schema Support
4 | - xs:choice: ignore the ability to choose and generate with all the elements as required(need to change the generated body as required)
5 | - xs:annotations: not supported
6 | - xs:attributes: Working for basic attributes
7 | - Not supported: Default and Fixed Values for Attributes, Optional and Required Attributes
8 | - xs:restrictions: Read base type only. Restrictions won’t apply
9 | - xs:extensions: Generates with some usability issues. Can edit via IDE
10 | - xs:complexType: If extended from the base, not generating 100% correct mapping, but can edit in the IDE
11 | - xs:complexContent: works but with limitations if nested extensions present
12 | - xs:simpleContent: works but with limitations if nested extensions present
13 | - xs:all: generates the mapping but ignores the maxOccures restrictions
14 | - xs:groups: generate the mapping without errors, group elements are ignored
15 | - xs:attributeGroups: generate the mapping without errors, group elements are ignored
16 | - xs:any: ignored but generated without errors
17 | - xs:anyAttribute: ignored but generated without errors
18 | - maxOccurs: only taken care of the unbounded case for arrays
19 | - minOccurs: ignored and generate the mapping
20 | - Mixed Content: ignored but generated normal XML payload
21 | - substitutionGroup: ignored and generated
22 | - Unions: are not supported
23 | - Enumeration: not supported
24 |
25 | Primitive Data types defined in XSD Schema Specification
26 | Following data types are treated as string:
27 | - anyURI
28 | - base64Binary
29 | - Duration
30 | - hexBinary
31 | - gDay
32 | - gMonth
33 | - gMonthDay
34 | - gYear
35 | - gYearMonth
36 | - NOTATION
37 | - QName
38 |
39 | First-class support
40 | - Boolean
41 | - Date
42 | - dateTime
43 | - Decimal
44 | - Double
45 | - Float
46 | - String
47 | - Time
48 |
49 | NOTE: All the not supported or partially generated items can be edited in the generated payload from Integration Studio IDE
50 |
--------------------------------------------------------------------------------
/src/test/resources/complex/arrays.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/test/resources/complex/choice.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/test/resources/complex/groups.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/test/resources/complex/invalid.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/test/resources/complex/nested.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSElement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import javax.xml.namespace.QName;
21 |
22 | /**
23 | * Model for represent Element in the given XSD
24 | */
25 | public class XSElement {
26 |
27 | QName name;
28 | QName type;
29 | QName refKey;
30 | boolean isOptional;
31 | XSDataType inlineComplexType;
32 | boolean isArray;
33 |
34 | public QName getName() {
35 |
36 | return name;
37 | }
38 |
39 | public void setName(QName name) {
40 |
41 | this.name = name;
42 | }
43 |
44 | public QName getType() {
45 |
46 | return type;
47 | }
48 |
49 | public void setType(QName type) {
50 |
51 | this.type = type;
52 | }
53 |
54 | public XSDataType getInlineComplexType() {
55 |
56 | return inlineComplexType;
57 | }
58 |
59 | public void setInlineComplexType(XSDataType inlineComplexType) {
60 |
61 | this.inlineComplexType = inlineComplexType;
62 | }
63 |
64 | public QName getRefKey() {
65 |
66 | return refKey;
67 | }
68 |
69 | public void setRefKey(QName refKey) {
70 |
71 | this.refKey = refKey;
72 | }
73 |
74 | public boolean isArray() {
75 | return isArray;
76 | }
77 |
78 | public void setArray(boolean array) {
79 | isArray = array;
80 | }
81 |
82 | public boolean isOptional() {
83 | return isOptional;
84 | }
85 |
86 | public void setOptional(boolean optional) {
87 | isOptional = optional;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/SOAPtoRESTConversionData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import io.swagger.v3.core.util.Yaml;
21 | import io.swagger.v3.oas.models.OpenAPI;
22 |
23 | import java.util.Map;
24 | import java.util.Set;
25 |
26 | /**
27 | * Data object that represent the SOAP Endpoint as OpenAPI including the soap request message format for all the
28 | * soap endpoints.
29 | */
30 | public class SOAPtoRESTConversionData {
31 |
32 | private final OpenAPI openAPI;
33 | private final Map soapRequestBodyMapping;
34 | private final String soapService;
35 | private final String soapPort;
36 |
37 | public SOAPtoRESTConversionData(OpenAPI openAPI, Map soapRequestBodyMapping,
38 | String soapService, String soapPort) {
39 |
40 | this.openAPI = openAPI;
41 | this.soapRequestBodyMapping = soapRequestBodyMapping;
42 | this.soapService = soapService;
43 | this.soapPort = soapPort;
44 | }
45 |
46 | public Set> getAllSOAPRequestBodies() {
47 |
48 | return soapRequestBodyMapping.entrySet();
49 | }
50 |
51 | public String getOASString() {
52 |
53 | return Yaml.pretty(openAPI);
54 | }
55 |
56 | public String getSoapService() {
57 |
58 | return soapService;
59 | }
60 |
61 | public String getSoapPort() {
62 |
63 | return soapPort;
64 | }
65 |
66 | public OpenAPI getOpenAPI() {
67 | return openAPI;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSDataType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import javax.xml.namespace.QName;
21 |
22 | /**
23 | * Model for represent Data Type in the given XSD
24 | */
25 | public class XSDataType {
26 |
27 | QName name;
28 | QName extensionBase;
29 | XSSequence xsSequence;
30 | XSChoice xsChoice;
31 | XSGroup xsGroup;
32 | boolean isSimpleType = false;
33 |
34 | public QName getName() {
35 |
36 | return name;
37 | }
38 |
39 | public void setName(QName name) {
40 |
41 | this.name = name;
42 | }
43 |
44 | public XSSequence getSequence() {
45 |
46 | return xsSequence;
47 | }
48 |
49 | public void setSequence(XSSequence sequence) {
50 |
51 | this.xsSequence = sequence;
52 | }
53 |
54 | public XSChoice getChoice() {
55 |
56 | return xsChoice;
57 | }
58 |
59 | public void setChoice(XSChoice choice) {
60 |
61 | this.xsChoice = choice;
62 | }
63 |
64 | public XSGroup getGroup() {
65 |
66 | return xsGroup;
67 | }
68 |
69 | public void setGroup(XSGroup group) {
70 |
71 | this.xsGroup = group;
72 | }
73 |
74 | public QName getExtensionBase() {
75 |
76 | return extensionBase;
77 | }
78 |
79 | public void setExtensionBase(QName extensionBase) {
80 |
81 | this.extensionBase = extensionBase;
82 | }
83 |
84 | public boolean isSimpleType() {
85 | return isSimpleType;
86 | }
87 |
88 | public void setSimpleType(boolean simpleType) {
89 | isSimpleType = simpleType;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/XSModel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import java.util.ArrayList;
21 | import java.util.List;
22 |
23 | /**
24 | * Model for represent the all the Data Types in the given XSD
25 | */
26 | public class XSModel {
27 |
28 | List elements = new ArrayList<>();
29 | List attributes = new ArrayList<>();
30 | List xsDataTypes = new ArrayList<>();
31 | List groups = new ArrayList<>();
32 | String targetNamespace;
33 |
34 | private boolean elementFormDefaultQualified = false;
35 |
36 | public void addElement(XSElement element) {
37 |
38 | elements.add(element);
39 | }
40 |
41 | public void addAttribute(XSAttribute attribute) {
42 |
43 | attributes.add(attribute);
44 | }
45 |
46 | public List getXsDataTypes() {
47 |
48 | return xsDataTypes;
49 | }
50 |
51 | public void addXSDataType(XSDataType complexType) {
52 |
53 | xsDataTypes.add(complexType);
54 | }
55 |
56 | public void addGroup(XSGroup group) {
57 |
58 | groups.add(group);
59 | }
60 |
61 | public List getGroups() {
62 | return groups;
63 | }
64 |
65 | public void setTargetNamespace(String targetNamespace) {
66 |
67 | this.targetNamespace = targetNamespace;
68 | }
69 |
70 | public List getElements() {
71 | return elements;
72 | }
73 |
74 | public boolean isElementFormDefaultQualified() {
75 |
76 | return elementFormDefaultQualified;
77 | }
78 |
79 | public void setElementFormDefaultQualified(boolean elementFormDefaultQualified) {
80 |
81 | this.elementFormDefaultQualified = elementFormDefaultQualified;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/test/resources/calculator/calculator.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/test/java/org/wso2/soaptorest/WSDLExceptionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import org.junit.jupiter.api.Test;
21 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
22 |
23 | import java.net.MalformedURLException;
24 | import java.net.URL;
25 |
26 | import static org.junit.jupiter.api.Assertions.assertThrows;
27 | import static org.junit.jupiter.api.Assertions.assertTrue;
28 |
29 | public class WSDLExceptionTest {
30 |
31 | @Test
32 | void invalidWSDLFileLocation() {
33 | Exception exception = assertThrows(SOAPToRESTException.class, () -> SOAPToRESTConverter.getSOAPtoRESTConversionData("invalid " +
34 | "file", "test api", "1.0.0"));
35 |
36 | String expectedMessage = "Error while reading WSDL document";
37 | String actualMessage = exception.getMessage();
38 |
39 | assertTrue(actualMessage.contains(expectedMessage));
40 | }
41 |
42 | @Test
43 | void invalidWSDLURLLocation() {
44 | Exception exception = assertThrows(MalformedURLException.class, () -> SOAPToRESTConverter.getSOAPtoRESTConversionData(new URL(
45 | "invalid url"), "test api", "1.0.0"));
46 |
47 | String expectedMessage = "invalid url";
48 | String actualMessage = exception.getMessage();
49 |
50 | assertTrue(actualMessage.contains(expectedMessage));
51 | }
52 |
53 | @Test
54 | void invalidXSDReferredFileLocation() {
55 | Exception exception = assertThrows(SOAPToRESTException.class, () -> SOAPToRESTConverter.getSOAPtoRESTConversionData("src/" +
56 | "test/resources/complex/invalid.wsdl", "Test API", "1.0.0"));
57 |
58 | String expectedMessage = "Cannot process the provide WSDL file";
59 | String actualMessage = exception.getMessage();
60 |
61 | assertTrue(actualMessage.contains(expectedMessage));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/resources/calculator-remote/calculator.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/WSDLInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import java.util.Set;
21 |
22 | /**
23 | * Information extracted from WSDL.
24 | */
25 | public class WSDLInfo {
26 |
27 | private String version;
28 | private boolean hasSoapBindingOperations;
29 | private boolean hasSoap12BindingOperations;
30 | private Set soapBindingOperations;
31 | private String soapService;
32 | private String soapPort;
33 |
34 | public String getVersion() {
35 |
36 | return version;
37 | }
38 |
39 | public void setVersion(String version) {
40 |
41 | this.version = version;
42 | }
43 |
44 | public void setHasSoapBindingOperations(boolean hasSoapBindingOperations) {
45 |
46 | this.hasSoapBindingOperations = hasSoapBindingOperations;
47 | }
48 |
49 | public boolean hasSoapBindingOperations() {
50 |
51 | return hasSoapBindingOperations;
52 | }
53 |
54 | public boolean isHasSoap12BindingOperations() {
55 |
56 | return hasSoap12BindingOperations;
57 | }
58 |
59 | public void setHasSoap12BindingOperations(boolean hasSoap12BindingOperations) {
60 |
61 | this.hasSoap12BindingOperations = hasSoap12BindingOperations;
62 | }
63 |
64 | public Set getSoapBindingOperations() {
65 |
66 | return soapBindingOperations;
67 | }
68 |
69 | public void setSoapBindingOperations(Set soapBindingOperations) {
70 |
71 | this.soapBindingOperations = soapBindingOperations;
72 | }
73 |
74 | public String getSoapService() {
75 |
76 | return this.soapService;
77 | }
78 |
79 | public void setSoapService(String soapService) {
80 |
81 | this.soapService = soapService;
82 | }
83 |
84 | public String getSoapPort() {
85 |
86 | return this.soapPort;
87 | }
88 |
89 | public void setSoapPort(String soapPort) {
90 |
91 | this.soapPort = soapPort;
92 | }
93 | }
--------------------------------------------------------------------------------
/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Purpose
2 | > Describe the problems, issues, or needs driving this feature/fix and include links to related issues in the following format: Resolves issue1, issue2, etc.
3 |
4 | ## Goals
5 | > Describe the solutions that this feature/fix will introduce to resolve the problems described above
6 |
7 | ## Approach
8 | > Describe how you are implementing the solutions. Include an animated GIF or screenshot if the change affects the UI (email documentation@wso2.com to review all UI text). Include a link to a Markdown file or Google doc if the feature write-up is too long to paste here.
9 |
10 | ## User stories
11 | > Summary of user stories addressed by this change>
12 |
13 | ## Release note
14 | > Brief description of the new feature or bug fix as it will appear in the release notes
15 |
16 | ## Documentation
17 | > Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact
18 |
19 | ## Training
20 | > Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable
21 |
22 | ## Certification
23 | > Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.
24 |
25 | ## Marketing
26 | > Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable
27 |
28 | ## Automation tests
29 | - Unit tests
30 | > Code coverage information
31 | - Integration tests
32 | > Details about the test cases and coverage
33 |
34 | ## Security checks
35 | - Followed secure coding standards in http://wso2.com/technical-reports/wso2-secure-engineering-guidelines? yes/no
36 | - Ran FindSecurityBugs plugin and verified report? yes/no
37 | - Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets? yes/no
38 |
39 | ## Samples
40 | > Provide high-level details about the samples related to this feature
41 |
42 | ## Related PRs
43 | > List any other related PRs
44 |
45 | ## Migrations (if applicable)
46 | > Describe migration steps and platforms on which migration has been tested
47 |
48 | ## Test environment
49 | > List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested
50 |
51 | ## Learning
52 | > Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/SOAPToRESTConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import io.swagger.v3.oas.models.OpenAPI;
21 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
22 | import org.wso2.soaptorest.models.SOAPtoRESTConversionData;
23 | import org.wso2.soaptorest.models.WSDLInfo;
24 | import org.wso2.soaptorest.utils.SOAPOperationExtractingUtil;
25 |
26 | import java.net.URL;
27 |
28 | public class SOAPToRESTConverter {
29 | public static SOAPtoRESTConversionData getSOAPtoRESTConversionData(URL url, String apiTitle, String apiVersion) throws
30 | SOAPToRESTException {
31 |
32 | WSDLProcessor wsdlProcessor = new WSDLProcessor();
33 | wsdlProcessor.init(url);
34 | SOAPOperationExtractingUtil soapOperationExtractingUtil = new SOAPOperationExtractingUtil();
35 | WSDLInfo wsdlInfo = soapOperationExtractingUtil.getWsdlInfo(wsdlProcessor.getWsdlDefinition());
36 | OpenAPI openAPI = OASGenerator.generateOpenAPIFromWSDL(wsdlInfo, wsdlProcessor.xsdDataModels, apiTitle,
37 | apiVersion);
38 | return SOAPRequestBodyGenerator.generateSOAPtoRESTConversionObjectFromOAS(openAPI, wsdlInfo.getSoapService(),
39 | wsdlInfo.getSoapPort());
40 | }
41 |
42 | public static SOAPtoRESTConversionData getSOAPtoRESTConversionData(String filePath, String apiTitle,
43 | String apiVersion) throws SOAPToRESTException {
44 |
45 | WSDLProcessor wsdlProcessor = new WSDLProcessor();
46 | wsdlProcessor.init(filePath);
47 | SOAPOperationExtractingUtil soapOperationExtractingUtil = new SOAPOperationExtractingUtil();
48 | WSDLInfo wsdlInfo = soapOperationExtractingUtil.getWsdlInfo(wsdlProcessor.getWsdlDefinition());
49 | OpenAPI openAPI = OASGenerator.generateOpenAPIFromWSDL(wsdlInfo, wsdlProcessor.xsdDataModels, apiTitle,
50 | apiVersion);
51 | return SOAPRequestBodyGenerator.generateSOAPtoRESTConversionObjectFromOAS(openAPI, wsdlInfo.getSoapService(),
52 | wsdlInfo.getSoapPort());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SOAP to REST Conversion Java Library
2 |
3 | ## Introduction
4 |
5 | This open source library is capable of converting SOAP backend service to REST backends. The library is written to get
6 | the SOAP Webservice contract using WSDL file and generate OpenAPI Specification
7 | (Swagger file) along with the required SOAP Request bodies that will convert the REST JSON input to SOAP message. There
8 | are two methods to convert the SOAP Endpoints. Either using the URL of the real SOAP backend or the Zip file contain all
9 | the WSDL files and respective XSD files.
10 |
11 | ## How to build
12 |
13 | Clone the repository and build the project using executing following command in terminal
14 |
15 | ```mvn clean install```
16 |
17 | Prerequisites
18 |
19 | * Maven 3.6.3 or higher (tested on 3.6.3)
20 | * Java 11.0 or higher (tested on java 11)
21 |
22 | ## How to use
23 |
24 | There are two methods in SOAPToRestConverter.java that convert the WSDL to REST Endpoint
25 |
26 | 1) Use the following method to generate REST service from WSDL URL
27 |
28 | ```java
29 | getSOAPtoRESTConversionData(URL url,String apiTitle,String apiVersion)
30 | ```
31 |
32 | 2) Use the following method to generate REST service from WSDL File
33 |
34 | ```java
35 | getSOAPtoRESTConversionData(String filePath,String apiTitle,String apiVersion)
36 | ```
37 |
38 | Both methods will return an object from SOAPtoRESTConversionData.java class which contains following
39 |
40 | ```java
41 | OpenAPI openAPI;
42 | Map soapRequestBodyMapping;
43 | String soapService;
44 | String soapPort;
45 | ```
46 |
47 | * ``openAPI``, ``soapService`` and ``soapPort`` are the respective representation of the SOAP endpoint
48 | * ``soapRequestBodyMapping`` contains a map of SOAPRequestElement for all the SOAP operations.
49 |
50 | ``SOAPRequestElement`` Contains following,
51 |
52 | ```java
53 | Document soapRequestBody;
54 | String soapAction;
55 | String soapNamespace;
56 | String nameSpace;
57 | ```
58 |
59 | ``Document `` contains ```org.w3c.dom.Document``` of the Request message that need to send to the SOAP backend under
60 | ``soapAction``. This Document contains the message with the placeholders for JSON input
61 |
62 | ## License
63 |
64 | ```
65 | Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
66 |
67 | WSO2 Inc. licenses this file to you under the Apache License,
68 | Version 2.0 (the "License"); you may not use this file except
69 | in compliance with the License.
70 | You may obtain a copy of the License at
71 |
72 | http://www.apache.org/licenses/LICENSE-2.0
73 |
74 | Unless required by applicable law or agreed to in writing,
75 | software distributed under the License is distributed on an
76 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
77 | KIND, either express or implied. See the License for the
78 | specific language governing permissions and limitations
79 | under the License.
80 | ```
81 |
82 |
--------------------------------------------------------------------------------
/src/test/resources/complex/nested.xsd:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/test/java/org/wso2/soaptorest/SOAPToRESTConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import org.apache.commons.lang3.StringUtils;
21 | import org.junit.jupiter.api.Test;
22 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
23 | import org.wso2.soaptorest.models.SOAPtoRESTConversionData;
24 |
25 | import java.net.MalformedURLException;
26 | import java.net.URL;
27 |
28 | import static org.junit.jupiter.api.Assertions.assertEquals;
29 | import static org.junit.jupiter.api.Assertions.assertTrue;
30 |
31 | class SOAPToRESTConverterTest {
32 |
33 | @Test
34 | void testFileGetSOAPtoRESTConversionData() throws SOAPToRESTException {
35 |
36 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData("src/test/resources" +
37 | "/calculator/calculator.wsdl", "Test API", "1.0.0");
38 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
39 | assertEquals(soaPtoRESTConversionData.getAllSOAPRequestBodies().size(), 4);
40 | assertEquals(soaPtoRESTConversionData.getSoapService(), "CalculatorService");
41 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "CalculatorPort");
42 |
43 | }
44 |
45 | @Test
46 | void testURLGetSOAPtoRESTConversionData() throws MalformedURLException, SOAPToRESTException {
47 |
48 | URL url = new URL("https://raw.githubusercontent.com/wso2/soap-to-rest/main/src/test/resources/calculator-remote/calculator.wsdl");
49 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData(url, "Test API", "1.0.0");
50 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
51 | assertEquals(soaPtoRESTConversionData.getAllSOAPRequestBodies().size(), 4);
52 | assertEquals(soaPtoRESTConversionData.getSoapService(), "CalculatorService");
53 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "CalculatorPort");
54 |
55 | }
56 |
57 | @Test
58 | void testIssue28() throws MalformedURLException, SOAPToRESTException {
59 |
60 | URL url = new URL(
61 | "https://raw.githubusercontent.com/wso2/soap-to-rest/main/src/test/resources/issue-28/failing.wsdl");
62 | SOAPtoRESTConversionData soaPtoRESTConversionData =
63 | SOAPToRESTConverter.getSOAPtoRESTConversionData(url, "Test API", "1.0.0");
64 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
65 | assertEquals(1, soaPtoRESTConversionData.getAllSOAPRequestBodies().size());
66 | assertEquals(soaPtoRESTConversionData.getSoapService(), "myServer");
67 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "myServerSOAP");
68 |
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/models/WSDLSOAPOperation.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.models;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * Extracted SOAP operation details representation.
24 | */
25 | public class WSDLSOAPOperation {
26 |
27 | private String name;
28 | private String soapBindingOpName;
29 | private String soapAction;
30 | private String targetNamespace;
31 | private String style;
32 | private String messageType;
33 | private String httpVerb;
34 | private List inputParameterModel;
35 | private List outputParameterModel;
36 |
37 | public WSDLSOAPOperation() {
38 |
39 | }
40 |
41 | public String getName() {
42 |
43 | return name;
44 | }
45 |
46 | public void setName(String name) {
47 |
48 | this.name = name;
49 | }
50 |
51 | public String getSoapAction() {
52 |
53 | return soapAction;
54 | }
55 |
56 | public void setSoapAction(String soapAction) {
57 |
58 | this.soapAction = soapAction;
59 | }
60 |
61 | public String getTargetNamespace() {
62 |
63 | return targetNamespace;
64 | }
65 |
66 | public void setTargetNamespace(String targetNamespace) {
67 |
68 | this.targetNamespace = targetNamespace;
69 | }
70 |
71 | public String getStyle() {
72 |
73 | return style;
74 | }
75 |
76 | public void setStyle(String style) {
77 |
78 | this.style = style;
79 | }
80 |
81 | public String getHttpVerb() {
82 |
83 | return httpVerb;
84 | }
85 |
86 | public void setHttpVerb(String httpVerb) {
87 |
88 | this.httpVerb = httpVerb;
89 | }
90 |
91 |
92 | public String getSoapBindingOpName() {
93 |
94 | return soapBindingOpName;
95 | }
96 |
97 | public void setSoapBindingOpName(String soapBindingOpName) {
98 |
99 | this.soapBindingOpName = soapBindingOpName;
100 | }
101 |
102 | public List getInputParameterModel() {
103 |
104 | return inputParameterModel;
105 | }
106 |
107 | public void setInputParameterModel(List inputParameterModel) {
108 |
109 | this.inputParameterModel = inputParameterModel;
110 | }
111 |
112 | public List getOutputParameterModel() {
113 |
114 | return outputParameterModel;
115 | }
116 |
117 | public void setOutputParameterModel(List outputParameterModel) {
118 |
119 | this.outputParameterModel = outputParameterModel;
120 | }
121 |
122 | public String getMessageType() {
123 |
124 | return messageType;
125 | }
126 |
127 | public void setMessageType(String messageType) {
128 |
129 | this.messageType = messageType;
130 | }
131 | }
132 |
133 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/utils/SOAPToRESTConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.utils;
19 |
20 | /**
21 | * Constants used for wsdl processing in soap to rest mapping.
22 | */
23 | public class SOAPToRESTConstants {
24 |
25 | public static final String EMPTY_STRING = "";
26 | public static final String SOAP_VERSION_11 = "1.1";
27 | public static final String SOAP_VERSION_12 = "1.2";
28 | public static final String SOAP11_NAMESPACE = "http://schemas.xmlsoap.org/soap/envelope/";
29 | public static final String SOAP12_NAMESPACE = "http://www.w3.org/2003/05/soap-envelope";
30 | public static final String X_NAMESPACE_QUALIFIED = "x-namespace-qualified";
31 |
32 | public static final String QUALIFIED = "qualified";
33 | public static final String ROOT_ELEMENT_PREFIX = "rootElement_";
34 | public static final String XMLNS = "xmlns";
35 | public static final String X_WSO2_UNIQUE_NAMESPACE = "x-wso2-empty-namespace";
36 | public static final String BASE_CONTENT_KEYWORD = "_base";
37 | public static final String ATTR_CONTENT_KEYWORD = "_attr";
38 | public static final String SOAP_RPC_MESSAGE_TYPE = "rpc";
39 | public static final String DEFAULT_DESCRIPTION = "Default Description";
40 | public static final String WSDL_VERSION_11 = "1.1";
41 |
42 | //OAS Constants
43 | public static final String DEFAULT_CONTENT_TYPE = "*/*";
44 | public static final String SOAP_ACTION = "soap-action";
45 | public static final String SOAP_OPERATION = "soap-operation";
46 | public static final String NAMESPACE = "namespace";
47 | public static final String WSO2_SOAP = "x-wso2-soap";
48 | public static final String SOAP_VERSION = "x-soap-version";
49 | public static final String SOAP_MESSAGE_TYPE = "x-soap-message-type";
50 | public static final String SOAP_STYLE = "x-soap-style";
51 |
52 | //Sequence Generator Constants
53 | public static final String NAMESPACE_SEPARATOR = ":";
54 | public static final String PATH_SEPARATOR = "/";
55 |
56 | public static final String NAMESPACE_PREFIX = "web";
57 | public static final String ARRAY_PLACEHOLDER = "ARRAY_PLACEHOLDER";
58 |
59 | // HTTP Constants
60 | public static final String HTTP_METHOD_POST = "POST";
61 | public static final String HTTP_METHOD_GET = "GET";
62 |
63 |
64 | //OAS Generator Constants
65 | public static final String OAS_DEFINITIONS_PREFIX = "#/components/schemas/";
66 | public static final String OAS_DEFINITIONS_ROOT_ELEMENT_PATH = "#/components/schemas/rootElement_";
67 | public static final String EXTENSION_NAME = "ExtensionObject";
68 | public static final String OAS_ALL_MEDIA_TYPE = "*/*";
69 | public static final String OBJECT_TYPE = "object";
70 | public static final String ARRAY_TYPE = "array";
71 | public static final String IF_PLACEHOLDER = "ifPlaceholder";
72 | public static final String ELSE_PLACEHOLDER = "elsePlaceholder";
73 | public static final String QUESTION_MARK_PLACEHOLDER = "questionPlaceholder";
74 | public static final String ATTRIBUTE_PLACEHOLDER = "attributePlaceholder";
75 | public static final String IS_EMPTY_ATTRIBUTE = "addIsEmptyCheck";
76 | public static final String VALUE_ATTRIBUTE = "valueAttribute";
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/test/resources/issue-28/failing.wsdl:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
35 |
37 |
39 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/test/resources/calculator/calculator.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/src/test/resources/calculator-remote/calculator.wsdl:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/src/test/java/org/wso2/soaptorest/ComplexWSDLTestCase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import org.apache.commons.lang3.StringUtils;
21 | import org.junit.jupiter.api.Test;
22 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
23 | import org.wso2.soaptorest.models.SOAPRequestElement;
24 | import org.wso2.soaptorest.models.SOAPtoRESTConversionData;
25 |
26 | import javax.xml.transform.OutputKeys;
27 | import javax.xml.transform.Transformer;
28 | import javax.xml.transform.TransformerException;
29 | import javax.xml.transform.TransformerFactory;
30 | import javax.xml.transform.dom.DOMSource;
31 | import javax.xml.transform.stream.StreamResult;
32 | import java.io.StringWriter;
33 | import java.util.List;
34 | import java.util.Map;
35 | import java.util.Set;
36 |
37 | import static org.junit.jupiter.api.Assertions.assertEquals;
38 | import static org.junit.jupiter.api.Assertions.assertTrue;
39 |
40 | class ComplexWSDLTestCase {
41 |
42 | @Test
43 | void testNestedWSDL() throws SOAPToRESTException {
44 |
45 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData("src/test/resources" +
46 | "/complex/nested.wsdl", "Test API", "1.0.0");
47 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
48 | assertEquals(soaPtoRESTConversionData.getAllSOAPRequestBodies().size(), 1);
49 | assertEquals(soaPtoRESTConversionData.getSoapService(), "nestedSampleService");
50 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "nestedSamplePort");
51 |
52 | }
53 |
54 | @Test
55 | void testArrayWSDL() throws SOAPToRESTException, TransformerException {
56 |
57 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData("src/test/resources" +
58 | "/complex/arrays.wsdl", "Test API", "1.0.0");
59 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
60 | assertEquals(soaPtoRESTConversionData.getAllSOAPRequestBodies().size(), 1);
61 | assertEquals(soaPtoRESTConversionData.getSoapService(), "arraysSampleService");
62 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "arraysSamplePort");
63 |
64 | Set> soapElementEntry = soaPtoRESTConversionData.getAllSOAPRequestBodies();
65 | for (Map.Entry requestElementEntry : soapElementEntry) {
66 | SOAPRequestElement soapRequestElement = requestElementEntry.getValue();
67 | StringWriter writer = new StringWriter();
68 | TransformerFactory tf = TransformerFactory.newInstance();
69 | Transformer transformer = tf.newTransformer();
70 | transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
71 |
72 | transformer.transform(new DOMSource(soapRequestElement.getSoapRequestBody()),
73 | new StreamResult(writer));
74 | String soapPayload = writer.getBuffer().toString();
75 | String complexInnerType = "";
76 | assertTrue(soapPayload.contains(complexInnerType));
77 | assertEquals("http://example.com/", soapRequestElement.getNamespace());
78 | assertEquals("http://schemas.xmlsoap.org/soap/envelope/", soapRequestElement.getSoapNamespace());
79 | assertEquals("", soapRequestElement.getSoapAction());
80 | }
81 | }
82 |
83 | @Test
84 | void testGroupWSDL() throws SOAPToRESTException {
85 |
86 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData("src/test/resources" +
87 | "/complex/groups.wsdl", "Test API", "1.0.0");
88 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
89 | assertEquals(soaPtoRESTConversionData.getAllSOAPRequestBodies().size(), 1);
90 | assertEquals(soaPtoRESTConversionData.getSoapService(), "groupsSampleService");
91 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "groupsSamplePort");
92 | }
93 |
94 | @Test
95 | void testChoiceWSDL() throws SOAPToRESTException {
96 |
97 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData("src/test/resources" +
98 | "/complex/choice.wsdl", "Test API", "1.0.0");
99 | assertTrue(StringUtils.isNotBlank(soaPtoRESTConversionData.getOASString()));
100 | assertEquals(soaPtoRESTConversionData.getAllSOAPRequestBodies().size(), 1);
101 | assertEquals(soaPtoRESTConversionData.getSoapService(), "choiceSampleService");
102 | assertEquals(soaPtoRESTConversionData.getSoapPort(), "choiceSamplePort");
103 | }
104 |
105 | @Test
106 | void testWSDLWithOptional() throws SOAPToRESTException {
107 | SOAPtoRESTConversionData soaPtoRESTConversionData = SOAPToRESTConverter.getSOAPtoRESTConversionData(
108 | "src/test/resources" + "/complex/nested.wsdl", "Test API", "1.0.0");
109 | Set> soapElementEntry = soaPtoRESTConversionData.getAllSOAPRequestBodies();
110 | List requiredValues = soaPtoRESTConversionData.getOpenAPI().getComponents()
111 | .getSchemas().get("innerType2").getRequired();
112 | assertTrue(requiredValues.contains("inner3"));
113 | assertTrue(requiredValues.contains("int3"));
114 | requiredValues = soaPtoRESTConversionData.getOpenAPI().getComponents().getSchemas()
115 | .get("FCUBS_HEADERType").getRequired();
116 | assertTrue(requiredValues.get(0).equals("PASSWORD"));
117 | }
118 | }
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/utils/ListJSONPaths.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.utils;
19 |
20 | import io.swagger.v3.oas.models.OpenAPI;
21 | import org.apache.commons.lang3.StringUtils;
22 | import org.json.JSONArray;
23 | import org.json.JSONObject;
24 |
25 | import io.swagger.oas.inflector.examples.models.ArrayExample;
26 | import io.swagger.oas.inflector.examples.models.Example;
27 | import io.swagger.oas.inflector.examples.models.ObjectExample;
28 |
29 | import java.util.ArrayList;
30 | import java.util.Iterator;
31 | import java.util.List;
32 | import java.util.Map;
33 |
34 | /**
35 | * Utility class to extract all the json paths of the given json string
36 | */
37 | public class ListJSONPaths {
38 |
39 | /**
40 | * This method will return a list of all the available json paths of the input json string
41 | *
42 | * @param json input json file
43 | * @return the arraylist of the available json paths
44 | */
45 | public static ArrayList getJsonPaths(String json) {
46 |
47 | ArrayList pathList = new ArrayList<>();
48 | JSONObject object = new JSONObject(json);
49 | if (json != JSONObject.NULL) {
50 | readObject(object, null, pathList);
51 | }
52 | return pathList;
53 | }
54 |
55 | private static void readObject(JSONObject object, String jsonPath, ArrayList pathList) {
56 |
57 | Iterator> keysItr = object.keys();
58 | String parentPath = jsonPath;
59 | if (keysItr.hasNext()) {
60 | while (keysItr.hasNext()) {
61 | String key = (String) keysItr.next();
62 | Object value = object.get(key);
63 | jsonPath = (jsonPath == null) ? key : parentPath + "." + key;
64 |
65 | if (value instanceof JSONArray) {
66 | readArray((JSONArray) value, jsonPath, pathList);
67 | } else if (value instanceof JSONObject) {
68 | readObject((JSONObject) value, jsonPath, pathList);
69 | } else {
70 | pathList.add(jsonPath);
71 | }
72 | }
73 | } else if (StringUtils.isNotBlank(jsonPath)) {
74 | pathList.add(jsonPath);
75 | }
76 | }
77 |
78 | private static void readArray(JSONArray array, String jsonPath, ArrayList pathList) {
79 |
80 | String parentPath = jsonPath;
81 | for (int i = 0; i < array.length(); i++) {
82 | Object value = array.get(i);
83 | jsonPath = parentPath + "[" + i + "]";
84 |
85 | if (value instanceof JSONArray) {
86 | readArray((JSONArray) value, jsonPath, pathList);
87 | } else if (value instanceof JSONObject) {
88 | readObject((JSONObject) value, jsonPath, pathList);
89 | } else {
90 | pathList.add(jsonPath);
91 | }
92 | }
93 | }
94 |
95 | /*
96 | * This method will return a list of all the available json paths of the input json string
97 | * @param example example object
98 | * @return the arraylist of the available json paths
99 | */
100 | public static ArrayList getJsonPathsFromExample(Example example, Map jsonPathSchemaMapping) {
101 | ArrayList pathList = new ArrayList<>();
102 | if (example != null) {
103 | listExamples("", example, pathList, jsonPathSchemaMapping);
104 | }
105 | return pathList;
106 | }
107 |
108 | /*
109 | * This method will return a list of all the available json paths of the input json string
110 | * @param parent parent json path
111 | * @param example example object
112 | * @param parameterJsonPathMapping list of json paths
113 | * @return the arraylist of the available json paths
114 | */
115 | public static void listExamples(String parent, Example example, ArrayList parameterJsonPathMapping
116 | , Map jsonPathSchemaMapping) {
117 | if (example != null) {
118 | if (SOAPToRESTConstants.OBJECT_TYPE.equals(example.getTypeName())) {
119 | Map values = ((ObjectExample) example).getValues();
120 | if (values != null) {
121 | for (Map.Entry entry : values.entrySet()) {
122 | String childKey = parent.isEmpty() ? entry.getKey() : parent + "." + entry.getKey();
123 | if (entry.getValue() != null && entry.getValue().getName() != null) {
124 | jsonPathSchemaMapping.put(childKey, entry.getValue().getName());
125 | }
126 | listExamples(childKey, entry.getValue(), parameterJsonPathMapping, jsonPathSchemaMapping);
127 | }
128 | } else if (StringUtils.isNotBlank(parent)) {
129 | parameterJsonPathMapping.add(parent);
130 | }
131 | } else if (SOAPToRESTConstants.ARRAY_TYPE.equals(example.getTypeName())) {
132 | List exampleArray = ((ArrayExample) example).getItems();
133 | String jsonPath;
134 | if (exampleArray.size() > 0) {
135 | for (int i = 0; i < exampleArray.size(); i++) {
136 | Example exampleItem = exampleArray.get(i);
137 | jsonPath = parent + "[" + i + "]";
138 | if (SOAPToRESTConstants.OBJECT_TYPE.equals(exampleItem.getTypeName())) {
139 | listExamples(jsonPath, exampleItem, parameterJsonPathMapping, jsonPathSchemaMapping);
140 | } else if (SOAPToRESTConstants.ARRAY_TYPE.equals(exampleItem.getTypeName())) {
141 | listExamples(jsonPath, exampleItem, parameterJsonPathMapping, jsonPathSchemaMapping);
142 | } else {
143 | parameterJsonPathMapping.add(jsonPath);
144 | }
145 | }
146 | }
147 | } else if (StringUtils.isNotBlank(parent)) {
148 | parameterJsonPathMapping.add(parent);
149 | }
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 | org.wso2
6 | wso2
7 | 1.4
8 |
9 | org.wso2
10 | soaptorest
11 | 1.8.1-SNAPSHOT
12 |
13 | scm:git:https://github.com/wso2/soap-to-rest.git
14 | scm:git:https://github.com/wso2/soap-to-rest.git
15 | https://github.com/wso2/soap-to-rest.git
16 | HEAD
17 |
18 |
19 |
20 | xerces.wso2
21 | xercesImpl
22 | ${xerces.wso2.version}
23 |
24 |
25 | wsdl4j
26 | wsdl4j
27 | ${org.wsdl4j.version}
28 |
29 |
30 | org.apache.woden.wso2
31 | woden
32 | ${apache.woden.version}
33 |
34 |
35 | org.wso2.orbit.io.swagger.v3
36 | swagger-parser
37 | ${swagger.parser.v3.version}
38 |
39 |
40 | org.wso2.orbit.io.swagger
41 | swagger-inflector-oas3
42 | ${swagger.inflector.oas3.version}
43 |
44 |
45 | org.json.wso2
46 | json
47 | ${json.orbit.version}
48 |
49 |
50 | org.junit.jupiter
51 | junit-jupiter
52 | ${junit.version}
53 | test
54 |
55 |
56 |
57 | 8
58 | 8
59 | 2.8.1.wso2v2
60 | 1.6.2
61 | 1.0.0.M9-wso2v1
62 | 2.0.30.wso2v1
63 | 2.0.5.wso2v1
64 | 3.0.0.wso2v1
65 | 5.8.2
66 |
67 |
68 |
69 | wso2-nexus
70 | WSO2 internal Repository
71 | https://maven.wso2.org/nexus/content/groups/wso2-public/
72 |
73 | true
74 | daily
75 | ignore
76 |
77 |
78 |
79 |
80 |
81 |
82 | org.apache.maven.plugins
83 | maven-release-plugin
84 |
85 | clean install
86 | true
87 |
88 |
89 |
90 | org.apache.maven.plugins
91 | maven-deploy-plugin
92 |
93 |
94 | org.apache.maven.plugins
95 | maven-compiler-plugin
96 |
97 | ${maven.compiler.source}
98 | ${maven.compiler.target}
99 |
100 |
101 |
102 | org.jacoco
103 | jacoco-maven-plugin
104 | 0.8.4
105 |
106 |
107 | default-prepare-agent-by-coverage-enforcer
108 |
109 | prepare-agent
110 |
111 |
112 | argLine
113 |
114 |
115 |
116 | default-report-by-coverage-enforcer
117 |
118 | report
119 |
120 |
121 | ${project.build.directory}/jacoco.exec
122 |
123 |
124 |
125 | default-check-by-coverage-enforcer
126 |
127 | check
128 |
129 |
130 | ${project.build.directory}/jacoco.exec
131 |
132 |
133 |
134 | BUNDLE
135 |
136 |
137 |
138 | LINE
139 | COVEREDRATIO
140 | 0.0
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 | maven-surefire-plugin
151 | 2.22.2
152 |
153 | ${argLine}
154 |
155 |
156 |
157 | maven-failsafe-plugin
158 | 2.22.2
159 |
160 |
161 | org.apache.maven.plugins
162 | maven-assembly-plugin
163 | 3.1.1
164 |
165 |
166 |
167 | jar-with-dependencies
168 |
169 |
170 |
171 |
172 |
173 | make-assembly
174 | package
175 |
176 | single
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | wso2.releases
187 | WSO2 internal Repository
188 | https://maven.wso2.org/nexus/content/repositories/releases/
189 |
190 | true
191 | daily
192 | ignore
193 |
194 |
195 |
196 | wso2.snapshots
197 | Apache Snapshot Repository
198 | https://maven.wso2.org/nexus/content/repositories/snapshots/
199 |
200 | true
201 | daily
202 |
203 |
204 | false
205 |
206 |
207 |
208 | wso2-nexus
209 | WSO2 internal Repository
210 | https://maven.wso2.org/nexus/content/groups/wso2-public/
211 |
212 | true
213 | daily
214 | ignore
215 |
216 |
217 |
218 |
219 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/utils/WSDLProcessingUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.utils;
19 |
20 | import com.ibm.wsdl.extensions.schema.SchemaReferenceImpl;
21 | import org.apache.ws.commons.schema.XmlSchema;
22 | import org.apache.ws.commons.schema.XmlSchemaCollection;
23 | import org.apache.xerces.impl.Constants;
24 | import org.slf4j.Logger;
25 | import org.slf4j.LoggerFactory;
26 | import org.w3c.dom.Document;
27 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
28 | import org.xml.sax.SAXException;
29 |
30 | import javax.wsdl.Definition;
31 | import javax.wsdl.Types;
32 | import javax.wsdl.extensions.schema.Schema;
33 | import javax.wsdl.extensions.schema.SchemaImport;
34 | import javax.xml.XMLConstants;
35 | import javax.xml.parsers.DocumentBuilder;
36 | import javax.xml.parsers.DocumentBuilderFactory;
37 | import javax.xml.parsers.ParserConfigurationException;
38 | import java.io.FileInputStream;
39 | import java.io.IOException;
40 | import java.io.InputStream;
41 | import java.net.URL;
42 | import java.util.*;
43 |
44 | /**
45 | * Utility class to read the WSDL file from URL or file system safely and read all imported XSD Schemas
46 | * and return them as {@link Document} and Set of {@link XmlSchema}
47 | */
48 | public class WSDLProcessingUtil {
49 |
50 | static Logger log = LoggerFactory.getLogger(WSDLProcessingUtil.class);
51 |
52 | /**
53 | * Returns a secured document builder to avoid XXE attacks
54 | *
55 | * @return secured document builder to avoid XXE attacks
56 | */
57 | private static DocumentBuilderFactory getSecuredDocumentBuilder() {
58 |
59 | DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
60 | dbf.setNamespaceAware(true);
61 | dbf.setXIncludeAware(false);
62 | dbf.setExpandEntityReferences(false);
63 | try {
64 | dbf.setFeature(Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE, false);
65 | dbf.setFeature(Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE, false);
66 | dbf.setFeature(Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE, false);
67 | dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
68 | } catch (ParserConfigurationException e) {
69 | // Skip throwing the error as this exception doesn't break actual DocumentBuilderFactory creation
70 | log.error("Failed to load XML Processor Feature " + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE + " or "
71 | + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE + " or " + Constants.LOAD_EXTERNAL_DTD_FEATURE, e);
72 | }
73 | return dbf;
74 | }
75 |
76 | /**
77 | * Returns an "XXE safe" built DOM XML object by reading the content from the provided file path.
78 | *
79 | * @param path path to fetch the content
80 | * @return an "XXE safe" built DOM XML object by reading the content from the provided file path
81 | * @throws SOAPToRESTException When error occurred while reading from file path
82 | */
83 | public static Document getSecuredParsedDocumentFromPath(String path, String systemId) throws SOAPToRESTException, IOException {
84 |
85 | InputStream inputStream = null;
86 | try {
87 | DocumentBuilderFactory factory = getSecuredDocumentBuilder();
88 | DocumentBuilder builder = factory.newDocumentBuilder();
89 | inputStream = new FileInputStream(path);
90 | return builder.parse(inputStream, systemId);
91 | } catch (ParserConfigurationException | IOException | SAXException e) {
92 | throw new SOAPToRESTException("Error while reading WSDL document", e);
93 | } finally {
94 | if (inputStream != null) {
95 | inputStream.close();
96 | }
97 | }
98 | }
99 |
100 | public static Document getSecuredParsedDocumentFromURL(URL url) throws SOAPToRESTException, IOException {
101 |
102 | InputStream inputStream = null;
103 | try {
104 | DocumentBuilderFactory factory = getSecuredDocumentBuilder();
105 | DocumentBuilder builder = factory.newDocumentBuilder();
106 | inputStream = url.openStream();
107 | return builder.parse(inputStream);
108 | } catch (ParserConfigurationException | IOException | SAXException e) {
109 | throw new SOAPToRESTException("Error while reading WSDL document", e);
110 | } finally {
111 | if (inputStream != null) {
112 | inputStream.close();
113 | }
114 | }
115 | }
116 |
117 | /**
118 | * This method will read the given WSDL definition and extract all the referred XSD files and create List of
119 | * XSD Schemas
120 | *
121 | * @param wsdlDefinition input WSDL definition
122 | * @return returns Set of {@link XmlSchema} objects of all the referred XSDs of the WSDL file
123 | */
124 | public static Set getXMLSchemasFromWSDL(Definition wsdlDefinition, String systemId) {
125 |
126 | Set schemaArrayList = new HashSet<>();
127 | Types types = wsdlDefinition.getTypes();
128 | List> typeList = new ArrayList<>();
129 | if (types != null) {
130 | typeList = types.getExtensibilityElements();
131 | }
132 | if (typeList != null) {
133 | for (Object ext : typeList) {
134 | if (ext instanceof Schema) {
135 | Schema schema = (Schema) ext;
136 | XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
137 | schemaArrayList.add(schemaCollection.read(schema.getElement(), systemId));
138 | // Process imported XSDs if available
139 | Map, ?> importedSchemas = schema.getImports();
140 | if (importedSchemas != null) {
141 | processImportedSchemas(importedSchemas, schemaArrayList);
142 | }
143 | List> schemaIncludes = schema.getIncludes();
144 | if (schemaIncludes != null) {
145 | processIncludedSchemas(schemaIncludes, schemaArrayList);
146 | }
147 | }
148 | }
149 | }
150 | return schemaArrayList;
151 | }
152 |
153 | private static void processImportedSchemas(Map, ?> importedSchemas, Set schemaArrayList) {
154 |
155 | for (Object importedSchemaObj : importedSchemas.keySet()) {
156 | String schemaUrl = (String) importedSchemaObj;
157 | if (importedSchemas.get(schemaUrl) != null) {
158 | Vector> vector = (Vector>) importedSchemas.get(schemaUrl);
159 | for (Object schemaVector : vector) {
160 | if (schemaVector instanceof SchemaImport) {
161 | Schema referencedSchema = ((SchemaImport) schemaVector).getReferencedSchema();
162 | if (referencedSchema != null && referencedSchema.getElement() != null) {
163 | String systemId = referencedSchema.getDocumentBaseURI();
164 | XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
165 | schemaArrayList.add(schemaCollection.read(referencedSchema.getElement(), systemId));
166 | Map, ?> nestedImportedSchemas = referencedSchema.getImports();
167 | if (nestedImportedSchemas != null) {
168 | processImportedSchemas(nestedImportedSchemas, schemaArrayList);
169 | }
170 | List> nestedSchemaIncludes = referencedSchema.getIncludes();
171 | if (nestedSchemaIncludes != null) {
172 | processIncludedSchemas(nestedSchemaIncludes, schemaArrayList);
173 | }
174 | } else {
175 | log.warn("Cannot access referenced schema for the schema defined at: " + schemaUrl);
176 | }
177 | }
178 | }
179 | }
180 | }
181 | }
182 |
183 | private static void processIncludedSchemas(List> schemaIncludes, Set schemaArrayList) {
184 |
185 | for (Object includedSchemaRef : schemaIncludes) {
186 | if (includedSchemaRef instanceof SchemaReferenceImpl) {
187 | Schema referencedSchema = ((SchemaReferenceImpl) includedSchemaRef).getReferencedSchema();
188 |
189 | if (referencedSchema != null && referencedSchema.getElement() != null) {
190 | String systemId = referencedSchema.getDocumentBaseURI();
191 | XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
192 | schemaArrayList.add(schemaCollection.read(referencedSchema.getElement(), systemId));
193 | Map, ?> nestedImportedSchemas = referencedSchema.getImports();
194 | if (nestedImportedSchemas != null) {
195 | processImportedSchemas(nestedImportedSchemas, schemaArrayList);
196 | }
197 | List> nestedSchemaIncludes = referencedSchema.getIncludes();
198 | if (nestedSchemaIncludes != null) {
199 | processIncludedSchemas(nestedSchemaIncludes, schemaArrayList);
200 | }
201 | }
202 | }
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/WSDLProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import org.apache.ws.commons.schema.*;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
24 | import org.wso2.soaptorest.models.*;
25 | import org.wso2.soaptorest.utils.SOAPToRESTConstants;
26 | import org.wso2.soaptorest.utils.WSDLProcessingUtil;
27 |
28 | import javax.wsdl.Definition;
29 | import javax.wsdl.WSDLException;
30 | import javax.wsdl.factory.WSDLFactory;
31 | import javax.wsdl.xml.WSDLReader;
32 | import javax.xml.namespace.QName;
33 | import java.io.File;
34 | import java.io.IOException;
35 | import java.net.URL;
36 | import java.util.ArrayList;
37 | import java.util.Iterator;
38 | import java.util.List;
39 | import java.util.Set;
40 |
41 | /**
42 | * The class that processes WSDL 1.1 documents
43 | */
44 | public class WSDLProcessor {
45 |
46 | private static final String JAVAX_WSDL_VERBOSE_MODE = "javax.wsdl.verbose";
47 | private static final String JAVAX_WSDL_IMPORT_DOCUMENTS = "javax.wsdl.importDocuments";
48 | private static volatile WSDLFactory wsdlFactoryInstance;
49 | Logger log = LoggerFactory.getLogger(WSDLProcessor.class);
50 | Set wsdlSchemaList;
51 | List xsdDataModels = new ArrayList<>();
52 | private Definition wsdlDefinition;
53 |
54 | public static WSDLFactory getWsdlFactoryInstance() throws SOAPToRESTException {
55 |
56 | if (wsdlFactoryInstance == null) {
57 | try {
58 | synchronized (WSDLProcessor.class) {
59 | if (wsdlFactoryInstance == null) {
60 | wsdlFactoryInstance = WSDLFactory.newInstance();
61 | }
62 | }
63 | } catch (WSDLException e) {
64 | throw new SOAPToRESTException("Error while instantiating WSDL 1.1 factory", e);
65 | }
66 | }
67 | return wsdlFactoryInstance;
68 | }
69 |
70 | /**
71 | * Initialize the processor based on a provided file path which contains WSDL file.
72 | *
73 | * @param path File path with WSDL file
74 | * @throws SOAPToRESTException Unexpected error while initialization
75 | */
76 | void init(String path) throws SOAPToRESTException {
77 |
78 | WSDLReader wsdlReader = getWsdlFactoryInstance().newWSDLReader();
79 |
80 | //Switch off the verbose mode
81 | wsdlReader.setFeature(JAVAX_WSDL_VERBOSE_MODE, false);
82 | wsdlReader.setFeature(JAVAX_WSDL_IMPORT_DOCUMENTS, false);
83 | try {
84 | File file = new File(path);
85 | String systemId = file.getParent();
86 | if (systemId == null) {
87 | systemId = "";
88 | }
89 | wsdlDefinition = wsdlReader.readWSDL(systemId, WSDLProcessingUtil.getSecuredParsedDocumentFromPath(path, systemId));
90 | initializeModels(wsdlDefinition, systemId);
91 | if (log.isDebugEnabled()) {
92 | log.debug("Successfully initialized the WSDL File from given path");
93 | }
94 | } catch (WSDLException | IOException e) {
95 | //This implementation class cannot process the WSDL.
96 | log.debug("Cannot process the WSDL by " + this.getClass().getName(), e);
97 | throw new SOAPToRESTException("Cannot process the provide WSDL file", e);
98 | }
99 | }
100 |
101 | /**
102 | * Initialize the processor based on a provided URL of the WSDL file.
103 | *
104 | * @param url URL of the WSDL file
105 | * @throws SOAPToRESTException Unexpected error while initialization
106 | */
107 | void init(URL url) throws SOAPToRESTException {
108 |
109 | WSDLReader wsdlReader = getWsdlFactoryInstance().newWSDLReader();
110 |
111 | //Switch off the verbose mode
112 | wsdlReader.setFeature(JAVAX_WSDL_VERBOSE_MODE, false);
113 | wsdlReader.setFeature(JAVAX_WSDL_IMPORT_DOCUMENTS, false);
114 | try {
115 | wsdlDefinition = wsdlReader.readWSDL(url.toString(),
116 | WSDLProcessingUtil.getSecuredParsedDocumentFromURL(url));
117 | initializeModels(wsdlDefinition, null);
118 | if (log.isDebugEnabled()) {
119 | log.debug("Successfully initialized the WSDL File from given URL");
120 | }
121 | } catch (WSDLException | IOException e) {
122 | //This implementation class cannot process the WSDL.
123 | log.debug("Cannot process the WSDL by " + this.getClass().getName(), e);
124 | throw new SOAPToRESTException("Cannot process the provide WSDL file", e);
125 | }
126 | }
127 |
128 | /**
129 | * This method will extract the XSD Schemas from the WSDL file and generate the data model
130 | *
131 | * @param wsdlDefinition input WSDL definition
132 | */
133 | public void initializeModels(Definition wsdlDefinition, String systemId) {
134 |
135 | wsdlSchemaList = WSDLProcessingUtil.getXMLSchemasFromWSDL(wsdlDefinition, systemId);
136 | for (XmlSchema xmlSchema : wsdlSchemaList) {
137 | // Process single XSD Schema file from the available schema list
138 | XSModel xsModel = new XSModel();
139 | xsModel.setTargetNamespace(xmlSchema.getTargetNamespace());
140 | xsModel.setElementFormDefaultQualified(
141 | SOAPToRESTConstants.QUALIFIED.equals(xmlSchema.getElementFormDefault().getValue()));
142 |
143 | //Process Elements in the XSD
144 | Iterator> elementsIterator = xmlSchema.getElements().getValues();
145 | while (elementsIterator.hasNext()) {
146 | Object xmlSchemaObject = elementsIterator.next();
147 | if (xmlSchemaObject instanceof XmlSchemaElement) {
148 | XSElement xsElement = processXmlSchemaElement((XmlSchemaElement) xmlSchemaObject);
149 | xsModel.addElement(xsElement);
150 | }
151 | }
152 |
153 | //Process Attributes in the XSD
154 | Iterator> attributesIterator = xmlSchema.getAttributes().getValues();
155 | while (attributesIterator.hasNext()) {
156 | Object xmlSchemaObject = attributesIterator.next();
157 | if (xmlSchemaObject instanceof XmlSchemaAttribute) {
158 | XSAttribute xsAttribute = processXmlSchemaAttribute((XmlSchemaAttribute) xmlSchemaObject);
159 | xsModel.addAttribute(xsAttribute);
160 | }
161 | }
162 |
163 | //Process XSD Group data type
164 | Iterator> groupIterator = xmlSchema.getGroups().getValues();
165 | while (groupIterator.hasNext()) {
166 | XSSequence xsSequence = new XSSequence();
167 | XSGroup xsGroup = new XSGroup();
168 | Object schemaGroupObject = groupIterator.next();
169 | if (schemaGroupObject instanceof XmlSchemaGroup) {
170 | XmlSchemaGroup xmlSchemaGroup = (XmlSchemaGroup) schemaGroupObject;
171 | xsGroup.setName(xmlSchemaGroup.getName());
172 | int numOfGroupElements = xmlSchemaGroup.getParticle().getItems().getCount();
173 | for (int i = 0; i < numOfGroupElements; i++) {
174 | XmlSchemaObject xmlSchemaObject = xmlSchemaGroup.getParticle().getItems().getItem(i);
175 | if (xmlSchemaObject instanceof XmlSchemaElement) {
176 | XSElement xsElement = processXmlSchemaElement((XmlSchemaElement) xmlSchemaObject);
177 | xsSequence.addElement(xsElement);
178 | }
179 | }
180 | xsGroup.addSequence(xsSequence);
181 | }
182 | xsModel.addGroup(xsGroup);
183 | }
184 |
185 | //Process Data Types defined in the schema
186 | Iterator> schemaTypeIterator = xmlSchema.getSchemaTypes().getValues();
187 | while (schemaTypeIterator.hasNext()) {
188 | Object schemaTypeObject = schemaTypeIterator.next();
189 | if (schemaTypeObject instanceof XmlSchemaType) {
190 | XSDataType xsDataType = processXSDataType((XmlSchemaType) schemaTypeObject);
191 | xsModel.addXSDataType(xsDataType);
192 | }
193 |
194 | }
195 | xsdDataModels.add(xsModel);
196 | }
197 | }
198 |
199 | private XSElement processXmlSchemaElement(XmlSchemaElement xmlSchemaElement) {
200 |
201 | XSElement xsElement = new XSElement();
202 | xsElement.setName(xmlSchemaElement.getQName());
203 | xsElement.setArray(xmlSchemaElement.getMaxOccurs() > 1);
204 | if (xmlSchemaElement.getSchemaTypeName() != null) {
205 | xsElement.setType(xmlSchemaElement.getSchemaTypeName());
206 | } else if (xmlSchemaElement.getSchemaType() != null) {
207 | // If the schema type is inline, then the Schema type name will be null
208 | XSDataType inlineComplexType = processXSDataType(xmlSchemaElement.getSchemaType());
209 | xsElement.setInlineComplexType(inlineComplexType);
210 | } else if (xmlSchemaElement.getRefName() != null) {
211 | xsElement.setRefKey(xmlSchemaElement.getRefName());
212 | } else {
213 | log.warn("Data type for the child element " + xmlSchemaElement.getName() + "did " + "not processed");
214 | }
215 | if (xmlSchemaElement.getMinOccurs() == 0) {
216 | xsElement.setOptional(true);
217 | }
218 | return xsElement;
219 | }
220 |
221 | public XSDataType processXSDataType(XmlSchemaType xmlSchemaType) {
222 |
223 | XSDataType xsDataType = new XSDataType();
224 | if (xmlSchemaType.getName() != null) {
225 | xsDataType.setName(xmlSchemaType.getQName());
226 | }
227 | if (xmlSchemaType instanceof XmlSchemaComplexType) {
228 | XmlSchemaComplexType complexType = (XmlSchemaComplexType) xmlSchemaType;
229 |
230 | //Process SimpleContent and ComplexContent
231 | XmlSchemaContentModel xmlSchemaContentModel = complexType.getContentModel();
232 | if (xmlSchemaContentModel != null) {
233 | XmlSchemaContent xmlSchemaContent = xmlSchemaContentModel.getContent();
234 | if (xmlSchemaContent instanceof XmlSchemaSimpleContentExtension) {
235 | XmlSchemaSimpleContentExtension simpleContentExtension =
236 | (XmlSchemaSimpleContentExtension) xmlSchemaContent;
237 | xsDataType.setExtensionBase(simpleContentExtension.getBaseTypeName());
238 | } else if (xmlSchemaContent instanceof XmlSchemaComplexContentExtension) {
239 | XmlSchemaComplexContentExtension complexContentExtension =
240 | (XmlSchemaComplexContentExtension) xmlSchemaContent;
241 | xsDataType.setExtensionBase(complexContentExtension.getBaseTypeName());
242 | }
243 | }
244 |
245 | // Process child elements of the complexTypes
246 | XmlSchemaParticle xmlSchemaParticle = complexType.getParticle();
247 | // Process XSD All and Sequence as single type since no need to support sequence in openAPI
248 | if (xmlSchemaParticle instanceof XmlSchemaAll || xmlSchemaParticle instanceof XmlSchemaSequence) {
249 | XmlSchemaGroupBase xmlSchemaGroupBase = (XmlSchemaGroupBase) complexType.getParticle();
250 | int numElements = xmlSchemaGroupBase.getItems().getCount();
251 | XSSequence xsSequence = new XSSequence();
252 | for (int i = 0; i < numElements; i++) {
253 | XmlSchemaObject xmlSchemaObject = xmlSchemaGroupBase.getItems().getItem(i);
254 | if (xmlSchemaObject instanceof XmlSchemaElement) {
255 | XSElement xsElement = processXmlSchemaElement((XmlSchemaElement) xmlSchemaObject);
256 | xsSequence.addElement(xsElement);
257 | }
258 | }
259 | xsDataType.setSequence(xsSequence);
260 | }
261 |
262 | //Process Choice types
263 | if (xmlSchemaParticle instanceof XmlSchemaChoice) {
264 | XmlSchemaChoice xmlSchemaChoice = (XmlSchemaChoice) xmlSchemaParticle;
265 | int numElements = xmlSchemaChoice.getItems().getCount();
266 | XSChoice xsChoice = new XSChoice();
267 | for (int i = 0; i < numElements; i++) {
268 | XmlSchemaObject xmlSchemaObject = xmlSchemaChoice.getItems().getItem(i);
269 | if (xmlSchemaObject instanceof XmlSchemaElement) {
270 | XSElement xsElement = processXmlSchemaElement((XmlSchemaElement) xmlSchemaObject);
271 | xsChoice.addElement(xsElement);
272 | }
273 | }
274 | xsDataType.setChoice(xsChoice);
275 | }
276 |
277 | //Process Group types
278 | if (xmlSchemaParticle instanceof XmlSchemaGroupRef) {
279 | XmlSchemaGroupRef xmlSchemaGroupRef = (XmlSchemaGroupRef) xmlSchemaParticle;
280 | XSGroup xsGroup = new XSGroup();
281 | xsGroup.setRefKey(xmlSchemaGroupRef.getRefName());
282 | xsDataType.setGroup(xsGroup);
283 | }
284 | }
285 |
286 | if (xmlSchemaType instanceof XmlSchemaSimpleType) {
287 | XmlSchemaSimpleType xmlSchemaTypeObject = (XmlSchemaSimpleType) xmlSchemaType;
288 | XSSequence xsSequence = new XSSequence();
289 | XSElement xsElement = new XSElement();
290 | xsElement.setName(xmlSchemaTypeObject.getQName());
291 | if (xmlSchemaTypeObject.getBaseSchemaTypeName() != null) {
292 | xsElement.setType(xmlSchemaTypeObject.getBaseSchemaTypeName());
293 | } else if (xmlSchemaTypeObject.getContent() != null) {
294 | if (xmlSchemaTypeObject.getContent() instanceof XmlSchemaSimpleTypeRestriction) {
295 | XmlSchemaSimpleTypeRestriction xmlSchemaSimpleTypeRestriction =
296 | (XmlSchemaSimpleTypeRestriction) xmlSchemaTypeObject.getContent();
297 | xsElement.setType(xmlSchemaSimpleTypeRestriction.getBaseTypeName());
298 | }
299 | }
300 | if (xsElement.getType() == null) {
301 | xsElement.setType(new QName("string"));
302 |
303 | }
304 | xsSequence.addElement(xsElement);
305 | xsDataType.setSequence(xsSequence);
306 | xsDataType.setSimpleType(true);
307 | }
308 | return xsDataType;
309 | }
310 |
311 | private XSAttribute processXmlSchemaAttribute(XmlSchemaAttribute xmlSchemaAttribute) {
312 |
313 | XSAttribute xsAttribute = new XSAttribute();
314 | xsAttribute.setName(xmlSchemaAttribute.getQName());
315 | if (xmlSchemaAttribute.getSchemaTypeName() != null) {
316 | xsAttribute.setType(xmlSchemaAttribute.getSchemaTypeName());
317 | } else if (xmlSchemaAttribute.getSchemaType() != null) {
318 | // If the schema type is inline, then the Schema type name will be null
319 | XSDataType inlineComplexType = processXSDataType(xmlSchemaAttribute.getSchemaType());
320 | xsAttribute.setInlineComplexType(inlineComplexType);
321 | } else if (xmlSchemaAttribute.getRefName() != null) {
322 | xsAttribute.setRefKey(xmlSchemaAttribute.getRefName());
323 | } else {
324 | log.warn("Data type for the child element " + xmlSchemaAttribute.getName() + "did " + "not processed");
325 | }
326 | return xsAttribute;
327 | }
328 |
329 | public Definition getWsdlDefinition() {
330 |
331 | return wsdlDefinition;
332 | }
333 | }
334 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/utils/SOAPOperationExtractingUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest.utils;
19 |
20 | import org.slf4j.Logger;
21 | import org.slf4j.LoggerFactory;
22 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
23 | import org.wso2.soaptorest.models.WSDLInfo;
24 | import org.wso2.soaptorest.models.WSDLParameter;
25 | import org.wso2.soaptorest.models.WSDLSOAPOperation;
26 |
27 | import javax.wsdl.*;
28 | import javax.wsdl.extensions.soap.SOAPBinding;
29 | import javax.wsdl.extensions.soap.SOAPOperation;
30 | import javax.wsdl.extensions.soap12.SOAP12Binding;
31 | import javax.wsdl.extensions.soap12.SOAP12Operation;
32 | import java.util.*;
33 |
34 | /**
35 | * Utility class to extract the SOAP Operations from the given WSDL Definition file
36 | */
37 | public class SOAPOperationExtractingUtil {
38 |
39 | static Logger log = LoggerFactory.getLogger(SOAPOperationExtractingUtil.class);
40 | String targetNamespace;
41 |
42 | /**
43 | * This method will return the extracted SOAP Operation details of the given WSDL definition
44 | *
45 | * @param wsdlDefinition input wsdl definition to extract the SOAP Operations
46 | * @return returns the {@link WSDLInfo} object carrying the info extracted from the WSDL file
47 | * @throws SOAPToRESTException exception will throw if the SOAP Operation detail extraction is not success
48 | */
49 | public WSDLInfo getWsdlInfo(Definition wsdlDefinition) throws SOAPToRESTException {
50 |
51 | WSDLInfo wsdlInfo = new WSDLInfo();
52 | if (wsdlDefinition != null) {
53 | Set soapOperations = getSoapBindingOperations(wsdlDefinition);
54 | //the current implementation only supports WSDL 1.1 version
55 | wsdlInfo.setVersion(SOAPToRESTConstants.WSDL_VERSION_11);
56 |
57 | if (!soapOperations.isEmpty()) {
58 | wsdlInfo.setSoapBindingOperations(soapOperations);
59 | }
60 | wsdlInfo.setHasSoapBindingOperations(hasSoapBindingOperations(wsdlDefinition));
61 | wsdlInfo.setHasSoap12BindingOperations(hasSoap12BindingOperations(wsdlDefinition));
62 |
63 | //only support for single service and a port per WSDL file, hence getting the first one
64 | Service service = (Service) wsdlDefinition.getServices().values().iterator().next();
65 | Port port = (Port) service.getPorts().values().iterator().next();
66 | wsdlInfo.setSoapService(service.getQName().getLocalPart());
67 | wsdlInfo.setSoapPort(port.getName());
68 |
69 | } else {
70 | throw new SOAPToRESTException("WSDL Definition is not initialized.");
71 | }
72 | return wsdlInfo;
73 | }
74 |
75 | /**
76 | * Retrieves all the operations defined in the provided WSDL definition.
77 | *
78 | * @param definition WSDL Definition
79 | * @return a set of {@link WSDLSOAPOperation} defined in the provided WSDL definition
80 | */
81 | private Set getSoapBindingOperations(Definition definition) throws SOAPToRESTException {
82 |
83 | targetNamespace = definition.getTargetNamespace();
84 | Set allOperations = new HashSet<>();
85 | for (Object bindingObj : definition.getAllBindings().values()) {
86 | if (bindingObj instanceof Binding) {
87 | Binding binding = (Binding) bindingObj;
88 | Set operations = getSOAPBindingOperations(binding);
89 | allOperations.addAll(operations);
90 | }
91 | }
92 | return allOperations;
93 | }
94 |
95 | /**
96 | * Retrieves all the operations defined in the provided Binding.
97 | *
98 | * @param binding WSDL binding
99 | * @return a set of {@link WSDLSOAPOperation} defined in the provided Binding
100 | */
101 | private Set getSOAPBindingOperations(Binding binding) throws SOAPToRESTException {
102 |
103 | Set allBindingOperations = new HashSet<>();
104 | if (binding.getExtensibilityElements() != null && binding.getExtensibilityElements().size() > 0) {
105 | List> extensibilityElements = binding.getExtensibilityElements();
106 | for (Object extensibilityElement : extensibilityElements) {
107 | if (extensibilityElement instanceof SOAPBinding || extensibilityElement instanceof SOAP12Binding) {
108 | for (Object opObj : binding.getBindingOperations()) {
109 | BindingOperation bindingOperation = (BindingOperation) opObj;
110 | WSDLSOAPOperation wsdlSoapOperation = getSOAPOperation(bindingOperation);
111 | if (wsdlSoapOperation != null) {
112 | allBindingOperations.add(wsdlSoapOperation);
113 | } else {
114 | log.warn("Unable to get soap operation details: " + bindingOperation.getName());
115 | }
116 | }
117 | }
118 | }
119 | } else {
120 | throw new SOAPToRESTException("Cannot further process to get soap binding operations");
121 | }
122 | return allBindingOperations;
123 | }
124 |
125 | /**
126 | * Retrieves WSDL operation given the soap binding operation
127 | *
128 | * @param bindingOperation {@link BindingOperation} object
129 | * @return a set of {@link WSDLSOAPOperation} defined in the provided Binding
130 | */
131 | private WSDLSOAPOperation getSOAPOperation(BindingOperation bindingOperation) {
132 |
133 | WSDLSOAPOperation wsdlOperation = null;
134 | if (bindingOperation.getExtensibilityElements().isEmpty() && bindingOperation.getOperation() != null) {
135 | Operation soapOperation = bindingOperation.getOperation();
136 | wsdlOperation = new WSDLSOAPOperation();
137 | wsdlOperation.setName(bindingOperation.getName());
138 | wsdlOperation.setTargetNamespace(getTargetNamespace(bindingOperation));
139 | wsdlOperation.setStyle(String.valueOf(soapOperation.getStyle()));
140 | wsdlOperation.setInputParameterModel(getSoapInputParameterModel(bindingOperation));
141 | wsdlOperation.setOutputParameterModel(getSoapOutputParameterModel(bindingOperation));
142 | wsdlOperation.setMessageType(getSoapMessageType(bindingOperation));
143 |
144 | } else {
145 | for (Object boExtElement : bindingOperation.getExtensibilityElements()) {
146 | if (boExtElement instanceof SOAPOperation) {
147 | SOAPOperation soapOperation = (SOAPOperation) boExtElement;
148 | wsdlOperation = new WSDLSOAPOperation();
149 | wsdlOperation.setName(bindingOperation.getName());
150 | wsdlOperation.setSoapAction(soapOperation.getSoapActionURI());
151 | wsdlOperation.setTargetNamespace(getTargetNamespace(bindingOperation));
152 | wsdlOperation.setStyle(soapOperation.getStyle());
153 | wsdlOperation.setInputParameterModel(getSoapInputParameterModel(bindingOperation));
154 | wsdlOperation.setOutputParameterModel(getSoapOutputParameterModel(bindingOperation));
155 | wsdlOperation.setMessageType(getSoapMessageType(bindingOperation));
156 | } else if (boExtElement instanceof SOAP12Operation) {
157 | SOAP12Operation soapOperation = (SOAP12Operation) boExtElement;
158 | wsdlOperation = new WSDLSOAPOperation();
159 | wsdlOperation.setName(bindingOperation.getName());
160 | wsdlOperation.setSoapAction(soapOperation.getSoapActionURI());
161 | wsdlOperation.setTargetNamespace(getTargetNamespace(bindingOperation));
162 | wsdlOperation.setStyle(soapOperation.getStyle());
163 | wsdlOperation.setInputParameterModel(getSoapInputParameterModel(bindingOperation));
164 | wsdlOperation.setOutputParameterModel(getSoapOutputParameterModel(bindingOperation));
165 | wsdlOperation.setMessageType(getSoapMessageType(bindingOperation));
166 | }
167 | }
168 | }
169 | return wsdlOperation;
170 | }
171 |
172 | /**
173 | * Gets the target namespace given the soap binding operation
174 | *
175 | * @param bindingOperation soap operation
176 | * @return target name space
177 | */
178 | private String getTargetNamespace(BindingOperation bindingOperation) {
179 |
180 | Operation operation = bindingOperation.getOperation();
181 | if (operation != null) {
182 | Input input = operation.getInput();
183 |
184 | if (input != null) {
185 | Message message = input.getMessage();
186 | if (message != null) {
187 | Map, ?> partMap = message.getParts();
188 |
189 | for (Map.Entry, ?> obj : partMap.entrySet()) {
190 | Part part = (Part) obj.getValue();
191 | if (part != null) {
192 | if (part.getElementName() != null) {
193 | return part.getElementName().getNamespaceURI();
194 | }
195 | }
196 | }
197 | }
198 | }
199 | }
200 | return targetNamespace;
201 | }
202 |
203 | /**
204 | * Gets swagger input parameter model for a given soap operation
205 | *
206 | * @param bindingOperation soap operation
207 | * @return list of swagger models for the parameters
208 | */
209 | private List getSoapInputParameterModel(BindingOperation bindingOperation) {
210 |
211 | List inputParameterModelList = new ArrayList<>();
212 | Operation operation = bindingOperation.getOperation();
213 | if (operation != null) {
214 | Input input = operation.getInput();
215 |
216 | if (input != null) {
217 | Message message = input.getMessage();
218 | if (message != null) {
219 | Map, ?> map = message.getParts();
220 |
221 | for (Map.Entry, ?> obj : map.entrySet()) {
222 | Part part = (Part) obj.getValue();
223 | if (part != null) {
224 | if (part.getElementName() != null) {
225 | inputParameterModelList.add(new WSDLParameter(part.getElementName(),
226 | WSDLParameter.MessageType.ELEMENT));
227 | } else {
228 | if (part.getTypeName() != null) {
229 | inputParameterModelList.add(new WSDLParameter(part.getTypeName(),
230 | WSDLParameter.MessageType.TYPE));
231 | }
232 | }
233 | }
234 | }
235 | }
236 | }
237 | }
238 | return inputParameterModelList;
239 | }
240 |
241 | /**
242 | * Gets swagger output parameter model for a given soap operation
243 | *
244 | * @param bindingOperation soap operation
245 | * @return list of swagger models for the parameters
246 | */
247 | private List getSoapOutputParameterModel(BindingOperation bindingOperation) {
248 |
249 | List outputParameterModelList = new ArrayList<>();
250 | Operation operation = bindingOperation.getOperation();
251 | if (operation != null) {
252 | Output output = operation.getOutput();
253 | if (output != null) {
254 | Message message = output.getMessage();
255 | if (message != null) {
256 | Map, ?> map = message.getParts();
257 |
258 | for (Map.Entry, ?> obj : map.entrySet()) {
259 | Part part = (Part) obj.getValue();
260 | if (part != null) {
261 | if (part.getElementName() != null) {
262 | outputParameterModelList.add(new WSDLParameter(part.getElementName(),
263 | WSDLParameter.MessageType.ELEMENT));
264 | } else {
265 | if (part.getTypeName() != null) {
266 | outputParameterModelList.add(new WSDLParameter(part.getTypeName(),
267 | WSDLParameter.MessageType.TYPE));
268 | }
269 | }
270 | }
271 | }
272 | }
273 | }
274 | }
275 | return outputParameterModelList;
276 | }
277 |
278 | /**
279 | * Gets message type for a given soap operation
280 | *
281 | * @param bindingOperation soap operation
282 | * @return String for message type
283 | */
284 | private String getSoapMessageType(BindingOperation bindingOperation) {
285 |
286 | Operation operation = bindingOperation.getOperation();
287 | String messageType = "";
288 | boolean hasRPCMessages = false;
289 | if (operation != null) {
290 | Input input = operation.getInput();
291 |
292 | if (input != null) {
293 | Message message = input.getMessage();
294 | if (message != null) {
295 | Map, ?> map = message.getParts();
296 |
297 | for (Map.Entry, ?> obj : map.entrySet()) {
298 | Part part = (Part) obj.getValue();
299 | if (part != null) {
300 | if (part.getElementName() != null) {
301 | messageType = "document";
302 | } else if (part.getTypeName() != null) {
303 | messageType = "rpc";
304 | hasRPCMessages = true;
305 | }
306 | }
307 | }
308 | }
309 | }
310 | }
311 | if (hasRPCMessages) {
312 | return "rpc";
313 | } else {
314 | return messageType;
315 | }
316 | }
317 |
318 | /**
319 | * Returns if the provided WSDL definition contains SOAP binding operations
320 | *
321 | * @return whether the provided WSDL definition contains SOAP binding operations
322 | */
323 | private boolean hasSoapBindingOperations(Definition wsdlDefinition) {
324 |
325 | if (wsdlDefinition == null) {
326 | return false;
327 | }
328 | for (Object bindingObj : wsdlDefinition.getAllBindings().values()) {
329 | if (bindingObj instanceof Binding) {
330 | Binding binding = (Binding) bindingObj;
331 | for (Object ex : binding.getExtensibilityElements()) {
332 | if (ex instanceof SOAPBinding) {
333 | return true;
334 | }
335 | }
336 | }
337 | }
338 | return false;
339 | }
340 |
341 | /**
342 | * Returns if the provided WSDL definition contains SOAP 1.2 binding operations
343 | *
344 | * @return whether the provided WSDL definition contains SOAP 1.2 binding operations
345 | */
346 | private boolean hasSoap12BindingOperations(Definition wsdlDefinition) {
347 |
348 | if (wsdlDefinition == null) {
349 | return false;
350 | }
351 | for (Object bindingObj : wsdlDefinition.getAllBindings().values()) {
352 | if (bindingObj instanceof Binding) {
353 | Binding binding = (Binding) bindingObj;
354 | for (Object ex : binding.getExtensibilityElements()) {
355 | if (ex instanceof SOAP12Binding) {
356 | return true;
357 | }
358 | }
359 | }
360 | }
361 | return false;
362 | }
363 | }
364 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/OASGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import io.swagger.v3.oas.models.*;
21 | import io.swagger.v3.oas.models.info.Info;
22 | import io.swagger.v3.oas.models.media.*;
23 | import io.swagger.v3.oas.models.parameters.RequestBody;
24 | import io.swagger.v3.oas.models.responses.ApiResponse;
25 | import io.swagger.v3.oas.models.responses.ApiResponses;
26 | import org.apache.commons.lang3.StringUtils;
27 | import org.slf4j.Logger;
28 | import org.slf4j.LoggerFactory;
29 | import org.wso2.soaptorest.models.*;
30 | import org.wso2.soaptorest.utils.SOAPToRESTConstants;
31 |
32 | import javax.xml.namespace.QName;
33 | import java.util.Arrays;
34 | import java.util.HashMap;
35 | import java.util.List;
36 | import java.util.Map;
37 | import java.util.Set;
38 |
39 | public class OASGenerator {
40 |
41 | static Logger log = LoggerFactory.getLogger(OASGenerator.class);
42 |
43 | /**
44 | * Generate the swagger from the WSDL info
45 | *
46 | * @param wsdlInfo WSDLInfo object which has parsed WSDL data
47 | * @return Generated the swagger from the WSDL info
48 | */
49 | public static OpenAPI generateOpenAPIFromWSDL(WSDLInfo wsdlInfo, List xsModel, String APITitle,
50 | String APIVersion) {
51 |
52 | Set operations;
53 | operations = wsdlInfo.getSoapBindingOperations();
54 | populateSoapOperationParameters(operations);
55 | OpenAPI openAPI = new OpenAPI();
56 | Paths paths = new Paths();
57 |
58 | for (WSDLSOAPOperation operation : operations) {
59 | PathItem pathItem = new PathItem();
60 | Operation swaggerOperation = new Operation();
61 | ObjectSchema inputModelSchema = new ObjectSchema();
62 | if (operation.getInputParameterModel() != null) {
63 | for (WSDLParameter inputQName : operation.getInputParameterModel()) {
64 | if (inputQName.getMessageType() == WSDLParameter.MessageType.TYPE) {
65 | Schema> inputProp = getDataTypesSchema(inputQName.getQName());
66 | inputModelSchema.addProperties("parameter", inputProp);
67 | } else {
68 | Schema> inputRefProp = new Schema<>();
69 | inputRefProp.setName(inputQName.getQName().getLocalPart().replaceAll("\\s+", ""));
70 | inputRefProp.set$ref(SOAPToRESTConstants.OAS_DEFINITIONS_ROOT_ELEMENT_PATH + inputQName.
71 | getQName().getLocalPart());
72 | inputModelSchema.addProperties(inputQName.getQName().getLocalPart(), inputRefProp);
73 | }
74 | }
75 | } else {
76 | inputModelSchema.set$ref(SOAPToRESTConstants.OAS_DEFINITIONS_PREFIX + operation.getName());
77 | }
78 |
79 | RequestBody requestBody = new RequestBody();
80 | requestBody.setRequired(true);
81 | Content content = new Content();
82 | MediaType mediaType = new MediaType();
83 | mediaType.setSchema(inputModelSchema);
84 | content.addMediaType(SOAPToRESTConstants.OAS_ALL_MEDIA_TYPE, mediaType);
85 | requestBody.setContent(content);
86 | swaggerOperation.setRequestBody(requestBody);
87 |
88 | //adding response
89 | ApiResponses responses = new ApiResponses();
90 | ApiResponse response = new ApiResponse();
91 | ObjectSchema outputModelSchema = new ObjectSchema();
92 | if (operation.getOutputParameterModel() != null) {
93 | for (WSDLParameter outputParamQName : operation.getOutputParameterModel()) {
94 | if (outputParamQName.getMessageType() == WSDLParameter.MessageType.TYPE) {
95 | Schema> outputProp = getDataTypesSchema(outputParamQName.getQName());
96 | outputModelSchema.addProperties("parameter", outputProp);
97 | } else {
98 | Schema> outputRefProp = new Schema<>();
99 | outputRefProp.setName(SOAPToRESTConstants.OAS_DEFINITIONS_ROOT_ELEMENT_PATH + outputParamQName.getQName().getLocalPart().replaceAll("\\s+", ""));
100 | outputRefProp.set$ref(
101 | SOAPToRESTConstants.OAS_DEFINITIONS_ROOT_ELEMENT_PATH + outputParamQName.getQName().getLocalPart());
102 | outputModelSchema.addProperties(outputParamQName.getQName().getLocalPart(), outputRefProp);
103 | }
104 | }
105 |
106 | } else {
107 | outputModelSchema.set$ref(SOAPToRESTConstants.OAS_DEFINITIONS_PREFIX + operation.getName());
108 | }
109 | Content outputContent = new Content();
110 | MediaType outputMediaType = new MediaType();
111 | outputMediaType.setSchema(outputModelSchema);
112 | outputContent.addMediaType(SOAPToRESTConstants.OAS_ALL_MEDIA_TYPE, outputMediaType);
113 | response.setContent(outputContent);
114 | response.setDescription(SOAPToRESTConstants.DEFAULT_DESCRIPTION);
115 | responses.setDefault(response);
116 | swaggerOperation.setResponses(responses);
117 | swaggerOperation.setOperationId(operation.getSoapBindingOpName());
118 | //setting vendor extensions
119 | Map extensions = new HashMap<>();
120 | extensions.put(SOAPToRESTConstants.SOAP_ACTION, operation.getSoapAction());
121 | extensions.put(SOAPToRESTConstants.SOAP_OPERATION, operation.getSoapBindingOpName());
122 | extensions.put(SOAPToRESTConstants.NAMESPACE, operation.getTargetNamespace());
123 | if (wsdlInfo.isHasSoap12BindingOperations()) {
124 | extensions.put(SOAPToRESTConstants.SOAP_VERSION, SOAPToRESTConstants.SOAP_VERSION_12);
125 | } else if (wsdlInfo.hasSoapBindingOperations()) {
126 | extensions.put(SOAPToRESTConstants.SOAP_VERSION, SOAPToRESTConstants.SOAP_VERSION_11);
127 | }
128 | extensions.put(SOAPToRESTConstants.SOAP_STYLE, operation.getStyle());
129 | extensions.put(SOAPToRESTConstants.SOAP_MESSAGE_TYPE, operation.getMessageType());
130 | Map extensionMap = new HashMap<>();
131 | extensionMap.put(SOAPToRESTConstants.WSO2_SOAP, extensions);
132 | swaggerOperation.setExtensions(extensionMap);
133 |
134 | if (operation.getHttpVerb().equals(SOAPToRESTConstants.HTTP_METHOD_GET)) {
135 | pathItem.setGet(swaggerOperation);
136 | } else {
137 | pathItem.setPost(swaggerOperation);
138 | }
139 | paths.addPathItem("/" + operation.getName(), pathItem);
140 | }
141 |
142 | openAPI.paths(paths);
143 | Info info = new Info();
144 | info.setTitle(APITitle != null ? APITitle : SOAPToRESTConstants.EMPTY_STRING);
145 | info.setVersion(APIVersion != null ? APIVersion : SOAPToRESTConstants.EMPTY_STRING);
146 | openAPI.info(info);
147 | openAPI.setComponents(generateOASSchemas(xsModel));
148 |
149 | return openAPI;
150 |
151 | }
152 |
153 | /**
154 | * gets parameters from the soap operation and populates them in {@link WSDLSOAPOperation}
155 | *
156 | * @param soapOperations soap binding operations
157 | */
158 | private static void populateSoapOperationParameters(Set soapOperations) {
159 |
160 | if (soapOperations != null) {
161 | for (WSDLSOAPOperation operation : soapOperations) {
162 | String resourcePath;
163 | String operationName = operation.getName();
164 | operation.setSoapBindingOpName(operationName);
165 | operation.setHttpVerb(SOAPToRESTConstants.HTTP_METHOD_POST);
166 | resourcePath = operationName;
167 | resourcePath = resourcePath.substring(0, 1).toLowerCase() + resourcePath.substring(1);
168 | operation.setName(resourcePath.replaceAll("\\s+", ""));
169 | if (log.isDebugEnabled()) {
170 | log.debug("REST resource path for SOAP operation: " + operationName + " is: " + resourcePath);
171 | }
172 | }
173 | } else {
174 | log.info("No SOAP operations found in the WSDL");
175 | }
176 | }
177 |
178 | private static Components generateOASSchemas(List xsModelList) {
179 |
180 | Components components = new Components();
181 |
182 | for (XSModel xsModel : xsModelList) {
183 | List xsDataTypeList = xsModel.getXsDataTypes();
184 | for (XSDataType xsDataType : xsDataTypeList) {
185 | Schema> schema = getSchemaForXSDataType(xsDataType, null, xsModel.isElementFormDefaultQualified());
186 | components.addSchemas(schema.getName(), schema);
187 | }
188 | List xsDataGroupList = xsModel.getGroups();
189 | for (XSGroup xsGroup : xsDataGroupList) {
190 | Schema> schema = new ObjectSchema();
191 | schema.setName(xsGroup.getName().getLocalPart());
192 | processXSGroup(xsGroup, schema, xsModel.isElementFormDefaultQualified());
193 | components.addSchemas(schema.getName(), schema);
194 | }
195 |
196 | if (xsModel.getElements().size() > 0) {
197 | //Process the elements defined in the root XSD and add 'rootElement_' prefix to identify uniquely
198 | for (XSElement xsElement : xsModel.getElements()) {
199 | Schema> schema = getSchemaForXSElement(xsElement, xsModel.isElementFormDefaultQualified());
200 | schema.setName("rootElement_" + xsElement.getName().getLocalPart().replaceAll("\\s+", ""));
201 | schema.setType("object");
202 | components.addSchemas(schema.getName(), schema);
203 |
204 | }
205 |
206 | }
207 | }
208 | return components;
209 | }
210 |
211 | private static Schema> getSchemaForXSDataType(XSDataType xsDataType, String parentName, boolean isElementFormDefaultQualified) {
212 | String schemaName;
213 | Schema> schema;
214 | if (xsDataType.getName() != null) {
215 | schemaName = xsDataType.getName().getLocalPart().replaceAll("\\s+", "");
216 | } else if (parentName != null) {
217 | schemaName = parentName;
218 | } else {
219 | schemaName = "Default_Object";
220 | }
221 | if (xsDataType.isSimpleType()) {
222 | schema = new StringSchema();
223 | schema.setName(schemaName);
224 | schema.setType("string");
225 | } else {
226 | schema = new ObjectSchema();
227 | schema.setName(schemaName);
228 | if (xsDataType.getExtensionBase() != null) {
229 | schema.addProperties(SOAPToRESTConstants.EXTENSION_NAME, getDataTypesSchema(xsDataType.getExtensionBase()));
230 | Map extensionStringObjectMap = new HashMap<>();
231 | XML xml = new XML();
232 | if (xsDataType.getName() != null && StringUtils.isNotBlank(xsDataType.getName().getNamespaceURI())) {
233 | xml.setNamespace(xsDataType.getName().getNamespaceURI());
234 | xml.setPrefix(xsDataType.getName().getPrefix());
235 | }
236 | extensionStringObjectMap.put(SOAPToRESTConstants.X_NAMESPACE_QUALIFIED, isElementFormDefaultQualified);
237 | schema.setXml(xml);
238 | schema.setExtensions(extensionStringObjectMap);
239 | }
240 | if (xsDataType.getSequence() != null) {
241 | processXSSequence(xsDataType.getSequence(), schema, isElementFormDefaultQualified);
242 | Map extensionStringObjectMap = new HashMap<>();
243 | XML xml = new XML();
244 | if (xsDataType.getName() != null && StringUtils.isNotBlank(xsDataType.getName().getNamespaceURI())) {
245 | xml.setNamespace(xsDataType.getName().getNamespaceURI());
246 | xml.setPrefix(xsDataType.getName().getPrefix());
247 | }
248 | extensionStringObjectMap.put(SOAPToRESTConstants.X_NAMESPACE_QUALIFIED, isElementFormDefaultQualified);
249 | schema.setXml(xml);
250 | schema.setExtensions(extensionStringObjectMap);
251 | }
252 | if (xsDataType.getChoice() != null) {
253 | processXSChoice(xsDataType.getChoice(), schema, isElementFormDefaultQualified);
254 | }
255 | if (xsDataType.getGroup() != null) {
256 | processXSGroup(xsDataType.getGroup(), schema, isElementFormDefaultQualified);
257 | }
258 | }
259 | return schema;
260 | }
261 |
262 | private static void processXSSequence(XSSequence xsSequence, Schema> parentSchema, boolean isElementFormDefaultQualified) {
263 |
264 | if (xsSequence.getElementList() != null) {
265 | List xsElementList = xsSequence.getElementList();
266 | for (XSElement xsElement : xsElementList) {
267 | Schema> innerSchema = getSchemaForXSElement(xsElement, isElementFormDefaultQualified);
268 | if (innerSchema != null) {
269 | parentSchema.addProperties(innerSchema.getName(), innerSchema);
270 | // if element is not optional, add it to the required list of parent schema
271 | if (!xsElement.isOptional() && xsElement.getName() != null) {
272 | if (parentSchema.getRequired() != null) {
273 | parentSchema.getRequired().add(xsElement.getName().getLocalPart());
274 | } else {
275 | parentSchema.setRequired(Arrays.asList(xsElement.getName().getLocalPart()));
276 | }
277 | }
278 | }
279 | }
280 | }
281 | if (xsSequence.getSequenceList() != null) {
282 | for (XSSequence innerXSequence : xsSequence.getSequenceList()) {
283 | processXSSequence(innerXSequence, parentSchema, isElementFormDefaultQualified);
284 | }
285 | }
286 | if (xsSequence.getChoiceList() != null) {
287 | List xsChoiceList = xsSequence.getChoiceList();
288 | for (XSChoice xsChoice : xsChoiceList) {
289 | processXSChoice(xsChoice, parentSchema, isElementFormDefaultQualified);
290 | }
291 | }
292 | }
293 |
294 | private static void processXSChoice(XSChoice xsChoice, Schema> parentSchema, boolean isElementFormDefaultQualified) {
295 |
296 | if (xsChoice.getSequenceList() != null) {
297 | for (XSSequence xsSequence : xsChoice.getSequenceList()) {
298 | processXSSequence(xsSequence, parentSchema, isElementFormDefaultQualified);
299 | }
300 | }
301 | if (xsChoice.getChoiceList() != null) {
302 | for (XSChoice innerXsChoice : xsChoice.getChoiceList()) {
303 | processXSChoice(innerXsChoice, parentSchema, isElementFormDefaultQualified);
304 | }
305 | }
306 | if (xsChoice.getGroupsList() != null) {
307 | for (XSGroup xsGroup : xsChoice.getGroupsList()) {
308 | processXSGroup(xsGroup, parentSchema, isElementFormDefaultQualified);
309 | }
310 | }
311 | if (xsChoice.getElementList() != null) {
312 | for (XSElement xsElement : xsChoice.getElementList()) {
313 | Schema> innerSchema = getSchemaForXSElement(xsElement, isElementFormDefaultQualified);
314 | parentSchema.addProperties(innerSchema.getName(), innerSchema);
315 | }
316 | }
317 | }
318 |
319 | private static void processXSGroup(XSGroup xsGroup, Schema> parentSchema, boolean isElementFormDefaultQualified) {
320 |
321 | if (xsGroup.getChoiceList() != null) {
322 | for (XSChoice xsChoice : xsGroup.getChoiceList()) {
323 | processXSChoice(xsChoice, parentSchema, isElementFormDefaultQualified);
324 | }
325 | }
326 | if (xsGroup.getSequenceList() != null) {
327 | for (XSSequence xsSequence : xsGroup.getSequenceList()) {
328 | processXSSequence(xsSequence, parentSchema, isElementFormDefaultQualified);
329 | }
330 | }
331 | if (xsGroup.getRefKey() != null) {
332 | parentSchema.set$ref(SOAPToRESTConstants.OAS_DEFINITIONS_PREFIX + xsGroup.getRefKey().getLocalPart());
333 | }
334 | }
335 |
336 | private static Schema> getSchemaForXSElement(XSElement xsElement, boolean isElementFormDefaultQualified) {
337 |
338 | Schema> schema = null;
339 | if (xsElement.getType() != null) {
340 | if (xsElement.isArray()) {
341 | ArraySchema arraySchema = new ArraySchema();
342 | arraySchema.setItems(getDataTypesSchema(xsElement.getType()));
343 | schema = arraySchema;
344 | } else {
345 | schema = getDataTypesSchema(xsElement.getType());
346 | }
347 | if (xsElement.getName() != null) {
348 | schema.setName(xsElement.getName().getLocalPart().replaceAll("\\s+", ""));
349 | }
350 | } else if (xsElement.getRefKey() != null) {
351 | schema = new Schema<>();
352 | schema.setName(xsElement.getRefKey().getLocalPart().replaceAll("\\s+", ""));
353 | schema.$ref(SOAPToRESTConstants.OAS_DEFINITIONS_PREFIX + xsElement.getRefKey().getLocalPart());
354 | } else if (xsElement.getInlineComplexType() != null) {
355 | schema = getSchemaForXSDataType(xsElement.getInlineComplexType(),
356 | xsElement.getName().getLocalPart().replaceAll("\\s+", ""), isElementFormDefaultQualified);
357 | }
358 | return schema;
359 | }
360 |
361 | public static Schema> getDataTypesSchema(QName type) {
362 |
363 | Schema> outputSchema;
364 | String dataType = type.getLocalPart();
365 | switch (dataType) {
366 | case "string":
367 | case "anyType":
368 | case "duration":
369 | case "time":
370 | case "gYearMonth":
371 | case "gMonthDay":
372 | case "gYear":
373 | case "gDay":
374 | case "gMonth":
375 | case "anyURI":
376 | case "QName":
377 | case "normalizedString":
378 | case "token":
379 | outputSchema = new StringSchema();
380 | outputSchema.setType("string");
381 | break;
382 | case "dateTime":
383 | outputSchema = new DateTimeSchema();
384 | outputSchema.setType("string");
385 | outputSchema.setFormat("date-time");
386 | break;
387 | case "date":
388 | outputSchema = new DateSchema();
389 | outputSchema.setType("string");
390 | outputSchema.setFormat("date");
391 | break;
392 | case "hexBinary":
393 | outputSchema = new StringSchema();
394 | outputSchema.setType("string");
395 | outputSchema.setFormat("binary");
396 | break;
397 | case "base64Binary":
398 | case "unsignedByte":
399 | outputSchema = new StringSchema();
400 | outputSchema.setType("string");
401 | outputSchema.setFormat("byte");
402 | break;
403 | case "integer":
404 | case "nonPositiveInteger":
405 | case "negativeInteger":
406 | case "positiveInteger":
407 | case "nonNegativeInteger":
408 | case "unsignedInt":
409 | case "int":
410 | case "short":
411 | case "unsignedShort":
412 | outputSchema = new IntegerSchema();
413 | outputSchema.setType("integer");
414 | outputSchema.setFormat("int32");
415 | break;
416 | case "long":
417 | case "unsignedLong":
418 | outputSchema = new IntegerSchema();
419 | outputSchema.setType("integer");
420 | outputSchema.setFormat("int64");
421 | break;
422 | case "boolean":
423 | outputSchema = new BooleanSchema();
424 | outputSchema.setType("boolean");
425 | break;
426 | case "decimal":
427 | case "float":
428 | outputSchema = new NumberSchema();
429 | outputSchema.setType("number");
430 | outputSchema.setFormat("float");
431 | break;
432 | case "double":
433 | outputSchema = new NumberSchema();
434 | outputSchema.setType("number");
435 | outputSchema.setFormat("double");
436 | break;
437 | default:
438 | outputSchema = new Schema<>();
439 | outputSchema.$ref(SOAPToRESTConstants.OAS_DEFINITIONS_PREFIX + type.getLocalPart());
440 | }
441 | return outputSchema;
442 | }
443 |
444 | }
445 |
--------------------------------------------------------------------------------
/src/main/java/org/wso2/soaptorest/SOAPRequestBodyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
3 | *
4 | * WSO2 Inc. licenses this file to you under the Apache License,
5 | * Version 2.0 (the "License"); you may not use this file except
6 | * in compliance with the License.
7 | * You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing,
12 | * software distributed under the License is distributed on an
13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 | * KIND, either express or implied. See the License for the
15 | * specific language governing permissions and limitations
16 | * under the License.
17 | */
18 | package org.wso2.soaptorest;
19 |
20 | import com.fasterxml.jackson.databind.module.SimpleModule;
21 | import io.swagger.oas.inflector.examples.ExampleBuilder;
22 | import io.swagger.oas.inflector.examples.models.Example;
23 | import io.swagger.oas.inflector.processors.JsonNodeExampleSerializer;
24 | import io.swagger.util.Json;
25 | import io.swagger.v3.core.util.Yaml;
26 | import io.swagger.v3.oas.models.OpenAPI;
27 | import io.swagger.v3.oas.models.Operation;
28 | import io.swagger.v3.oas.models.PathItem;
29 | import io.swagger.v3.oas.models.Paths;
30 | import io.swagger.v3.oas.models.media.Schema;
31 | import io.swagger.v3.oas.models.parameters.Parameter;
32 | import io.swagger.v3.oas.models.parameters.QueryParameter;
33 | import org.apache.commons.lang3.StringUtils;
34 | import org.slf4j.Logger;
35 | import org.slf4j.LoggerFactory;
36 | import org.w3c.dom.Document;
37 | import org.w3c.dom.Element;
38 | import org.w3c.dom.Node;
39 | import org.w3c.dom.NodeList;
40 | import org.wso2.soaptorest.exceptions.SOAPToRESTException;
41 | import org.wso2.soaptorest.models.SOAPRequestElement;
42 | import org.wso2.soaptorest.models.SOAPtoRESTConversionData;
43 | import org.wso2.soaptorest.utils.ListJSONPaths;
44 | import org.wso2.soaptorest.utils.SOAPToRESTConstants;
45 |
46 | import javax.xml.parsers.DocumentBuilder;
47 | import javax.xml.parsers.DocumentBuilderFactory;
48 | import javax.xml.parsers.ParserConfigurationException;
49 | import java.io.StringWriter;
50 | import java.util.ArrayList;
51 | import java.util.HashMap;
52 | import java.util.List;
53 | import java.util.Map;
54 |
55 | import static org.wso2.soaptorest.utils.SOAPToRESTConstants.ATTRIBUTE_PLACEHOLDER;
56 | import static org.wso2.soaptorest.utils.SOAPToRESTConstants.IF_PLACEHOLDER;
57 | import static org.wso2.soaptorest.utils.SOAPToRESTConstants.IS_EMPTY_ATTRIBUTE;
58 | import static org.wso2.soaptorest.utils.SOAPToRESTConstants.QUESTION_MARK_PLACEHOLDER;
59 | import static org.wso2.soaptorest.utils.SOAPToRESTConstants.VALUE_ATTRIBUTE;
60 |
61 | /**
62 | * Class that reads OpenAPI and generate soap request payloads
63 | */
64 | public class SOAPRequestBodyGenerator {
65 |
66 | private static final Logger log = LoggerFactory.getLogger(SOAPRequestBodyGenerator.class);
67 | private static String soapMessageType = SOAPToRESTConstants.EMPTY_STRING;
68 | private static String soapStyle = SOAPToRESTConstants.EMPTY_STRING;
69 |
70 | /**
71 | * Generates {@link SOAPtoRESTConversionData} with a map of SOAP payloads with JSON paths of REST payloads for
72 | * all generated REST endpoint. Mapping is done using Operation ID of REST service.
73 | *
74 | * @param openAPI open api definition of api
75 | * @return SOAPtoRESTConversionData Object that represent the OpenAPI with SOAP payloads which are needed
76 | * for SOAP backend calls
77 | * @throws SOAPToRESTException throws {@link SOAPToRESTException} if exception occur while generating SOAP
78 | * payloads
79 | */
80 | public static SOAPtoRESTConversionData generateSOAPtoRESTConversionObjectFromOAS(OpenAPI openAPI,
81 | String soapService,
82 | String soapPort) throws
83 | SOAPToRESTException {
84 |
85 | Map requestBodies = new HashMap<>();
86 | Paths paths = openAPI.getPaths();
87 |
88 | // Configure serializers
89 | SimpleModule simpleModule = new SimpleModule().addSerializer(new JsonNodeExampleSerializer());
90 | Json.mapper().registerModule(simpleModule);
91 | Yaml.mapper().registerModule(simpleModule);
92 | Map jsonPathAndSchemaMap = new HashMap<>();
93 |
94 | for (String pathName : paths.keySet()) {
95 | PathItem path = paths.get(pathName);
96 | List operationMap = path.readOperations();
97 | for (Operation operation : operationMap) {
98 | ArrayList parameterJsonPathMapping = new ArrayList<>();
99 | Map queryParameters = new HashMap<>();
100 | String operationId = operation.getOperationId();
101 |
102 | //get vendor extensions
103 | Map vendorExtensions = operation.getExtensions();
104 | Object vendorExtensionObj = vendorExtensions.get(SOAPToRESTConstants.WSO2_SOAP);
105 |
106 | String soapAction = SOAPToRESTConstants.EMPTY_STRING;
107 | String namespace = SOAPToRESTConstants.EMPTY_STRING;
108 | String soapVersion = SOAPToRESTConstants.EMPTY_STRING;
109 | if (vendorExtensionObj != null) {
110 | soapAction =
111 | (String) ((HashMap, ?>) vendorExtensionObj).get(SOAPToRESTConstants.SOAP_ACTION);
112 | namespace =
113 | (String) ((HashMap, ?>) vendorExtensionObj).get(SOAPToRESTConstants.NAMESPACE);
114 | soapVersion =
115 | (String) ((HashMap, ?>) vendorExtensionObj).get(SOAPToRESTConstants.SOAP_VERSION);
116 | soapMessageType =
117 | (String) ((HashMap, ?>) vendorExtensionObj).get(SOAPToRESTConstants.SOAP_MESSAGE_TYPE);
118 | soapStyle =
119 | (String) ((HashMap, ?>) vendorExtensionObj).get(SOAPToRESTConstants.SOAP_STYLE);
120 | }
121 | String soapNamespace = SOAPToRESTConstants.SOAP12_NAMESPACE;
122 | if (StringUtils.isNotBlank(soapVersion) && SOAPToRESTConstants.SOAP_VERSION_11.equals(soapVersion)) {
123 | soapNamespace = SOAPToRESTConstants.SOAP11_NAMESPACE;
124 | }
125 |
126 | List parameters = operation.getParameters();
127 |
128 | if (parameters != null) {
129 | for (Parameter parameter : parameters) {
130 | String name = parameter.getName();
131 |
132 | if (parameter instanceof QueryParameter) {
133 | String type = parameter.getSchema().getType();
134 | queryParameters.put(name, type);
135 | }
136 | }
137 | } else {
138 | try {
139 | Schema> model =
140 | operation.getRequestBody().getContent().get(SOAPToRESTConstants.
141 | DEFAULT_CONTENT_TYPE).getSchema();
142 | Example example = ExampleBuilder.fromSchema(model, openAPI.getComponents().getSchemas());
143 | parameterJsonPathMapping = ListJSONPaths.getJsonPathsFromExample(example, jsonPathAndSchemaMap);
144 | } catch (Exception e) {
145 | throw new SOAPToRESTException("Cannot generate JSON body from the OpenAPI", e);
146 | }
147 |
148 | }
149 |
150 | Document soapRequestBody = createSOAPRequestXMLForOperation(parameterJsonPathMapping, queryParameters,
151 | namespace, operationId, openAPI, jsonPathAndSchemaMap );
152 |
153 | iterateChildNodes(soapRequestBody.getDocumentElement(), soapRequestBody);
154 | requestBodies.put(operationId, new SOAPRequestElement(soapRequestBody, soapAction, namespace,
155 | soapNamespace));
156 | }
157 | }
158 | return new SOAPtoRESTConversionData(openAPI, requestBodies, soapService, soapPort);
159 | }
160 |
161 | /**
162 | * Iterate through the given document and wrap the possible empty elements with <#if> statements.
163 | * @param node Current node
164 | * @param document Root document
165 | */
166 | private static void iterateChildNodes(Node node, Document document) {
167 | // Get the child nodes of the current node
168 | NodeList childNodes = node.getChildNodes();
169 |
170 | // Iterate over the child nodes
171 | for (int i = 0; i < childNodes.getLength(); i++) {
172 | Node childNode = childNodes.item(i);
173 |
174 | // Check if the element has the attribute "addIsEmptyCheck" with value "true"
175 | if (childNode instanceof Element) {
176 | Element element = (Element) childNode;
177 | if (element.hasAttribute(IS_EMPTY_ATTRIBUTE) &&
178 | element.getAttribute(IS_EMPTY_ATTRIBUTE).equals("true")) {
179 | // Create a new element <#if>
180 | String value = null;
181 | if (element.hasAttribute(VALUE_ATTRIBUTE)) {
182 | String nodeName = element.getNodeName();
183 | // remove namespace from the node name
184 | if (nodeName.contains(":")) {
185 | nodeName = nodeName.split(":")[1];
186 | }
187 | value = "${payload." + element.getAttribute(VALUE_ATTRIBUTE) + "." + nodeName + "}";
188 | element.removeAttribute(VALUE_ATTRIBUTE);
189 | }
190 | element.removeAttribute(IS_EMPTY_ATTRIBUTE);
191 |
192 | Element newElement = document.createElement(IF_PLACEHOLDER);
193 | // remove ${} from the value and append has_content check
194 | newElement.setAttribute(ATTRIBUTE_PLACEHOLDER, value.substring(2, value.length() - 1) +
195 | QUESTION_MARK_PLACEHOLDER + "has_content");
196 |
197 | Node parentNode = element.getParentNode();
198 | parentNode.replaceChild(newElement, element);
199 | newElement.appendChild(element);
200 |
201 | iterateChildNodes(newElement, document);
202 | } else {
203 | iterateChildNodes(element, document);
204 | }
205 | } else {
206 | iterateChildNodes(childNode, document);
207 | }
208 | }
209 | }
210 | private static Document createSOAPRequestXMLForOperation(ArrayList parameterJsonPathMapping, Map queryPathParamMapping, String namespace, String operationId, OpenAPI openAPI,
212 | Map jsonPathAndSchemaMap) throws SOAPToRESTException {
213 |
214 | DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
215 | DocumentBuilder docBuilder;
216 | StringWriter stringWriter = new StringWriter();
217 | boolean isNamespaceQualified = false;
218 | boolean isRootComplexType = false;
219 | Document doc;
220 | try {
221 | docBuilder = docFactory.newDocumentBuilder();
222 | doc = docBuilder.newDocument();
223 | Element rootElement = null;
224 | if (SOAPToRESTConstants.SOAP_RPC_MESSAGE_TYPE.equalsIgnoreCase(soapMessageType) ||
225 | SOAPToRESTConstants.SOAP_RPC_MESSAGE_TYPE.equalsIgnoreCase(soapStyle) ||
226 | parameterJsonPathMapping.isEmpty()) {
227 | rootElement = doc.createElementNS(namespace,
228 | SOAPToRESTConstants.NAMESPACE_PREFIX +
229 | SOAPToRESTConstants.NAMESPACE_SEPARATOR + operationId);
230 | doc.appendChild(rootElement);
231 | }
232 | for (String parameter : parameterJsonPathMapping) {
233 | String[] parameterTreeNodes = parameter.split("\\.");
234 |
235 | Element prevElement = rootElement;
236 | int elemPos = 0;
237 | int length = parameterTreeNodes.length;
238 | if (length > 0 && !isRootComplexType) {
239 | isRootComplexType = true;
240 | }
241 | String currentJSONPath = "payload";
242 | String notEscapedJSONPath = "payload";
243 | for (int i = 0; i < length; i++) {
244 | String parameterTreeNode = parameterTreeNodes[i];
245 | boolean isArray = false;
246 | currentJSONPath = currentJSONPath.isEmpty() ? escapeFreeMarkerTemplate(parameterTreeNode) :
247 | currentJSONPath + "." + escapeFreeMarkerTemplate(parameterTreeNode);
248 | notEscapedJSONPath = notEscapedJSONPath.isEmpty() ? parameterTreeNode :
249 | notEscapedJSONPath + "." + parameterTreeNode;
250 | if (parameterTreeNode.endsWith("[0]")) {
251 | isArray = true;
252 | parameterTreeNode = parameterTreeNode.replace("[0]", "");
253 | }
254 | Schema> schema = openAPI.getComponents().getSchemas().get(parameterTreeNode);
255 | // Since we add the elements defined in the root XSD with the 'rootElement_' prefix, we need to
256 | // check for the schema with the prefix if the schema is not found.
257 | if (schema == null) {
258 | schema = openAPI.getComponents().getSchemas()
259 | .get(SOAPToRESTConstants.ROOT_ELEMENT_PREFIX + parameterTreeNode);
260 | }
261 | if (schema != null) {
262 | Map vendorExtensions = schema.getExtensions();
263 | if (vendorExtensions != null && vendorExtensions.get(SOAPToRESTConstants.X_NAMESPACE_QUALIFIED) != null
264 | && Boolean.parseBoolean(vendorExtensions.get(SOAPToRESTConstants.X_NAMESPACE_QUALIFIED).
265 | toString())) {
266 | isNamespaceQualified = true;
267 | }
268 | }
269 | Schema> parentSchema = null;
270 | boolean needIsEmptyCheck = false;
271 | // Check parent schema for required fields and wrap with isEmpty check if required
272 | if (prevElement != null) {
273 | String mapKey = parameterTreeNode;
274 | // payload. is 8 characters long
275 | if (notEscapedJSONPath.length() > 8 + parameterTreeNode.length()) {
276 | mapKey = notEscapedJSONPath.substring(8, notEscapedJSONPath.length()
277 | - parameterTreeNode.length() - 1);
278 | }
279 | parentSchema = openAPI.getComponents().getSchemas().get(jsonPathAndSchemaMap.get(mapKey));
280 | if (parentSchema == null) {
281 | // check for the schema inside parent object's schema
282 | String parentKey = mapKey.substring(0, mapKey.lastIndexOf('.'));
283 | if (!StringUtils.isEmpty(parentKey)) {
284 | Schema> enclosingSchema = openAPI.getComponents().getSchemas()
285 | .get(jsonPathAndSchemaMap.get(parentKey));
286 | if (enclosingSchema != null && enclosingSchema.getProperties() != null &&
287 | enclosingSchema.getProperties().containsKey(prevElement.getLocalName())) {
288 | parentSchema = enclosingSchema.getProperties().get(prevElement.getLocalName());
289 | }
290 | }
291 | }
292 | if (parentSchema != null && (parentSchema.getRequired() == null ||
293 | !parentSchema.getRequired().contains(parameterTreeNode))) {
294 | needIsEmptyCheck = true;
295 | }
296 | }
297 |
298 | String payloadPrefix = "${";
299 | if (StringUtils.isNotBlank(parameterTreeNode)) {
300 | if (SOAPToRESTConstants.ATTR_CONTENT_KEYWORD.equalsIgnoreCase(parameterTreeNode)) {
301 | String attName = parameterTreeNodes[++i];
302 | prevElement.setAttribute(attName, payloadPrefix + currentJSONPath + "}");
303 | break;
304 | }
305 | if (SOAPToRESTConstants.BASE_CONTENT_KEYWORD.equalsIgnoreCase(parameterTreeNode)) {
306 | prevElement.setTextContent(payloadPrefix + currentJSONPath + "}");
307 | break;
308 | }
309 | Element element;
310 |
311 | if (isNamespaceQualified) {
312 | element = doc.createElementNS(namespace,
313 | SOAPToRESTConstants.NAMESPACE_PREFIX +
314 | SOAPToRESTConstants.NAMESPACE_SEPARATOR + parameterTreeNode);
315 | } else if (isRootComplexType) {
316 | element = doc.createElementNS(namespace,
317 | SOAPToRESTConstants.NAMESPACE_PREFIX +
318 | SOAPToRESTConstants.NAMESPACE_SEPARATOR + parameterTreeNode);
319 | isRootComplexType = false;
320 | } else {
321 | element = doc.createElement( parameterTreeNode);
322 | }
323 | if (isArray) {
324 | element.setAttribute(SOAPToRESTConstants.ARRAY_PLACEHOLDER,
325 | currentJSONPath.replace("[0]", ""));
326 | currentJSONPath = escapeFreeMarkerTemplate(parameterTreeNode);
327 | }
328 |
329 | String xPathOfNode = StringUtils.EMPTY;
330 | if (doc.getElementsByTagName(element.getTagName()).getLength() > 0) {
331 | xPathOfNode = getXpath(doc.getElementsByTagName(element.getTagName()).item(0));
332 | xPathOfNode = xPathOfNode.replaceAll("/+", ".");
333 | if (xPathOfNode.startsWith(".")) {
334 | xPathOfNode = xPathOfNode.substring(1);
335 | }
336 | if (xPathOfNode.contains(operationId + ".")) {
337 | xPathOfNode = xPathOfNode.replace(operationId + ".", "");
338 | }
339 | }
340 |
341 | if (doc.getElementsByTagName(element.getTagName()).getLength() > 0 &&
342 | parameter.contains(xPathOfNode) &&
343 | rootElement != doc.getElementsByTagName(element.getTagName()).item(0)) {
344 | prevElement = (Element) doc.getElementsByTagName(element.getTagName()).item(0);
345 | } else {
346 | if (elemPos == length - 1) {
347 | element.setTextContent(payloadPrefix + currentJSONPath + "}");
348 | }
349 | if (needIsEmptyCheck) {
350 | String path = "";
351 | for (int j = 0; j < i; j++) {
352 | path = path.concat(escapeFreeMarkerTemplate(parameterTreeNodes[j])).concat(".");
353 | }
354 | element.setAttribute(IS_EMPTY_ATTRIBUTE, "true");
355 | if (path.length() == 0) {
356 | element.setAttribute(VALUE_ATTRIBUTE, "");
357 | } else {
358 | element.setAttribute(VALUE_ATTRIBUTE, path.substring(0, path.length() - 1));
359 | }
360 | }
361 | if (prevElement != null) {
362 | prevElement.appendChild(element);
363 | } else {
364 | if (element.getLocalName() != null && !StringUtils.contains(element.getLocalName(), "null")) {
365 | doc.appendChild(element);
366 | }
367 | }
368 | prevElement = element;
369 | }
370 | elemPos++;
371 | }
372 | }
373 | }
374 | if (parameterJsonPathMapping.isEmpty()) {
375 | for (String queryParam : queryPathParamMapping.keySet()) {
376 | Element element = doc.createElementNS(namespace,
377 | SOAPToRESTConstants.NAMESPACE_PREFIX +
378 | SOAPToRESTConstants.NAMESPACE_SEPARATOR + queryParam);
379 | element.setTextContent("${uri.var." + queryParam + "}");
380 | if (rootElement != null) {
381 | rootElement.appendChild(element);
382 | } else {
383 | doc.appendChild(element);
384 | }
385 | }
386 | } else if (queryPathParamMapping.size() > 0) {
387 | log.warn("Query parameters along with the body parameter is not allowed");
388 | }
389 | } catch (ParserConfigurationException e) {
390 | throw new SOAPToRESTException("Error occurred when building in sequence xml", e);
391 | }
392 | if (log.isDebugEnabled()) {
393 | log.debug("parameter mapping for used in payload factory for soap operation:" + operationId + " is " +
394 | stringWriter);
395 | }
396 |
397 | return doc;
398 | }
399 |
400 | private static String getXpath(Node node) {
401 |
402 | if (node != null) {
403 | Node parent = node.getParentNode();
404 | if (parent == null && node.getLocalName() != null) {
405 | return node.getLocalName();
406 | } else if (node.getLocalName() != null) {
407 | return getXpath(parent) + SOAPToRESTConstants.PATH_SEPARATOR + node.getLocalName();
408 | } else {
409 | return getXpath(parent);
410 | }
411 | }
412 | return SOAPToRESTConstants.EMPTY_STRING;
413 | }
414 |
415 | /**
416 | * Escape the FreeMarker template. Since FreeMarker 2.3.22 the variable name can also contain minus (-), dot (.)
417 | * , and colon (:) at any position, but these must be escaped with a preceding backslash (\)
418 | *
419 | * @param template free marker template
420 | * @return escaped template
421 | */
422 | private static String escapeFreeMarkerTemplate(String template) {
423 |
424 | return template.replace("-", "\\-").replace(".", "\\.")
425 | .replace(":", "\\:");
426 | }
427 | }
428 |
--------------------------------------------------------------------------------