diff --git a/pom.xml b/pom.xml
index c810af8..102970b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
com.apigee.edge.config
apigee-config-maven-plugin
- 2.5.1-SNAPSHOT
+ 2.6.0-SNAPSHOT
maven-plugin
apigee-config-maven-plugin
Plugin to manage configuration in Apigee
diff --git a/samples/APIandConfig/HelloWorld/edge.json b/samples/APIandConfig/HelloWorld/edge.json
index 757025f..758c4dc 100644
--- a/samples/APIandConfig/HelloWorld/edge.json
+++ b/samples/APIandConfig/HelloWorld/edge.json
@@ -80,8 +80,8 @@
"description":"Echo Product",
"attributes":[
{
- "name": "access",
- "value": "public"
+ "name":"access",
+ "value":"public"
}
],
"environments":[
@@ -91,33 +91,35 @@
"quota":"10000",
"quotaInterval":"1",
"quotaTimeUnit":"month",
- "operationGroup": {
- "operationConfigs": [
- {
- "apiSource": "HelloWorld",
- "operations": [
- {
- "resource": "/",
- "methods": [
- "GET"
- ]
- }
+ "operationGroup":{
+ "operationConfigs":[
+ {
+ "apiSource":"HelloWorld",
+ "operations":[
+ {
+ "resource":"/",
+ "methods":[
+ "GET"
+ ]
+ }
],
- "quota": {
- "limit": "1000",
- "interval": "1",
- "timeUnit": "month"
+ "quota":{
+ "limit":"1000",
+ "interval":"1",
+ "timeUnit":"month"
},
- "attributes": [
- {
- "name": "foo",
- "value": "bar"
- }
+ "attributes":[
+ {
+ "name":"foo",
+ "value":"bar"
+ }
]
- }
+ }
]
- },
- "scopes":[]
+ },
+ "scopes":[
+
+ ]
},
{
"name":"EchoProduct-legacy",
@@ -132,8 +134,8 @@
"value":"Echo Product Legacy"
},
{
- "name": "access",
- "value": "public"
+ "name":"access",
+ "value":"public"
}
],
"description":"Echo Product Legacy",
@@ -148,7 +150,9 @@
"quota":"10000",
"quotaInterval":"1",
"quotaTimeUnit":"month",
- "scopes":[]
+ "scopes":[
+
+ ]
}
],
"kvms":[
@@ -253,6 +257,50 @@
}
]
},
+ "apiCategories":[
+ "echo",
+ "sample",
+ "foo"
+ ],
+ "apiDocs":[
+ {
+ "title":"Sample Doc",
+ "description":"Sample description",
+ "anonAllowed":true,
+ "imageUrl":"",
+ "requireCallbackUrl":true,
+ "published":true,
+ "apiProductName":"weatherProduct",
+ "categories":[
+ "foo"
+ ],
+ "oasDocumentation":{
+ "spec":{
+ "displayName":"sample-doc-spec",
+ "file":"./specs/openapi.yaml"
+ }
+ }
+ },
+ {
+ "title":"Sample GQL",
+ "description":"Sample GraphQL",
+ "anonAllowed":true,
+ "imageUrl":"",
+ "requireCallbackUrl":true,
+ "published":true,
+ "apiProductName":"demo",
+ "categories":[
+ "bar"
+ ],
+ "graphqlDocumentation":{
+ "schema":{
+ "displayName":"sample-doc-spec",
+ "file":"./specs/schema.graphql"
+ },
+ "endpointUri":"https://demo.google.com/graphql"
+ }
+ }
+ ],
"importKeys":{
"john@example.com":[
{
diff --git a/samples/APIandConfig/HelloWorld/specs/openapi.yaml b/samples/APIandConfig/HelloWorld/specs/openapi.yaml
new file mode 100644
index 0000000..ab73985
--- /dev/null
+++ b/samples/APIandConfig/HelloWorld/specs/openapi.yaml
@@ -0,0 +1,144 @@
+openapi: 3.0.0
+info:
+ description: OpenAPI Specification for the Apigee mock target service endpoint.
+ version: 1.0.0
+ title: Mock Target API
+paths:
+ /:
+ get:
+ summary: View personalized greeting
+ operationId: View a personalized greeting
+ description: View a personalized greeting for the specified or guest user.
+ parameters:
+ - name: user
+ in: query
+ description: Your user name.
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success
+ /help:
+ get:
+ summary: Get help
+ operationId: Get help
+ description: View help information about available resources in HTML format.
+ responses:
+ "200":
+ description: Success
+ /user:
+ get:
+ summary: View personalized greeting
+ operationId: View personalized greeting
+ description: View a personalized greeting for the specified or guest user.
+ parameters:
+ - name: user
+ in: query
+ description: Your user name.
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success
+ /iloveapis:
+ get:
+ summary: View API affirmation
+ operationId: View API affirmation
+ description: View API affirmation in HTML format.
+ responses:
+ "200":
+ description: Success
+ /ip:
+ get:
+ summary: View IP address
+ operationId: View IP address
+ description: View the IP address of the client in JSON format.
+ responses:
+ "200":
+ description: Success
+ /xml:
+ get:
+ summary: View XML response
+ operationId: View XML response
+ description: View a sample response in XML format.
+ responses:
+ "200":
+ description: Success
+ /json:
+ get:
+ summary: View JSON response
+ operationId: View JSON response
+ description: View a sample response in JSON format.
+ responses:
+ "200":
+ description: Success
+ /echo:
+ get:
+ summary: View request headers and body
+ operationId: View request headers and body
+ description: View the request headers and body in JSON format.
+ responses:
+ "200":
+ description: Success
+ post:
+ summary: Send request and view request headers and body
+ operationId: Send request and view request headers and body
+ description: "Send a request and view the resulting request headers and body in JSON
+ format.
+The request payload can be specified using one of the
+ following formats: application/json, application/x-www-form-urlencoded,
+ or application/xml."
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/request-body"
+ description: Request payload in application/json,
+ application/x-www-form-urlencoded, or application/xml format.
+ required: true
+ responses:
+ "200":
+ description: Success
+ "/statuscode/{code}":
+ get:
+ summary: View status code and message
+ operationId: View status code and message
+ description: View status code and message for the specified value.
+ parameters:
+ - name: code
+ in: path
+ description: HTTP status code.
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success
+ /auth:
+ get:
+ security:
+ - basicAuth: []
+ summary: Validate access using basic authentication
+ operationId: Validate access using basic authentication
+ description: Validate access using basic authentication.
+ responses:
+ "200":
+ description: Success
+servers:
+ - url: http://mocktarget.apigee.net
+ - url: https://mocktarget.apigee.net
+components:
+ securitySchemes:
+ basicAuth:
+ type: http
+ description: HTTP Basic Authentication.
+ scheme: basic
+ schemas:
+ request-body:
+ properties:
+ replace-me:
+ type: object
+ description: Replace with request payload in application/json,
+ application/x-www-form-urlencoded, or application/xml format.
\ No newline at end of file
diff --git a/samples/APIandConfig/HelloWorld/specs/schema.graphql b/samples/APIandConfig/HelloWorld/specs/schema.graphql
new file mode 100644
index 0000000..96da1bb
--- /dev/null
+++ b/samples/APIandConfig/HelloWorld/specs/schema.graphql
@@ -0,0 +1,12 @@
+type Query {
+ greeting:String
+ students:[Student]
+}
+
+type Student {
+ id:ID!
+ firstName:String
+ lastName:String
+ password:String
+ collegeId:String
+}
\ No newline at end of file
diff --git a/samples/APIandConfig/shared-pom.xml b/samples/APIandConfig/shared-pom.xml
index 17c21ec..c5ea568 100644
--- a/samples/APIandConfig/shared-pom.xml
+++ b/samples/APIandConfig/shared-pom.xml
@@ -69,7 +69,7 @@
com.apigee.edge.config
apigee-config-maven-plugin
- 2.5.0
+ 2.6.0-SNAPSHOT
create-config-targetserver
@@ -148,6 +148,20 @@
importKeys
+
+ create-portal-categories
+ install
+
+ apicategories
+
+
+
+ create-portal-docs
+ install
+
+ apidocs
+
+
@@ -165,6 +179,7 @@
oauth
${bearer}
${file}
+ ${siteId}
override
@@ -179,6 +194,7 @@
oauth
${bearer}
${file}
+ ${siteId}
override
diff --git a/samples/EdgeConfig/resources/edge/org/apiCategories.json b/samples/EdgeConfig/resources/edge/org/apiCategories.json
new file mode 100644
index 0000000..98d1d28
--- /dev/null
+++ b/samples/EdgeConfig/resources/edge/org/apiCategories.json
@@ -0,0 +1,4 @@
+[
+ "foo",
+ "bar"
+]
\ No newline at end of file
diff --git a/samples/EdgeConfig/resources/edge/org/apiDocs.json b/samples/EdgeConfig/resources/edge/org/apiDocs.json
new file mode 100644
index 0000000..2e5951d
--- /dev/null
+++ b/samples/EdgeConfig/resources/edge/org/apiDocs.json
@@ -0,0 +1,39 @@
+[
+ {
+ "title": "Sample Doc",
+ "description": "Sample description",
+ "anonAllowed": true,
+ "imageUrl": "",
+ "requireCallbackUrl": true,
+ "published": true,
+ "apiProductName": "weatherProduct",
+ "categories": [
+ "foo"
+ ],
+ "oasDocumentation": {
+ "spec": {
+ "displayName": "sample-openapi",
+ "file": "./specs/openapi.yaml"
+ }
+ }
+ },
+ {
+ "title": "Sample GQL",
+ "description": "Sample GraphQL",
+ "anonAllowed": true,
+ "imageUrl": "",
+ "requireCallbackUrl": true,
+ "published": true,
+ "apiProductName": "demo",
+ "categories": [
+ "bar"
+ ],
+ "graphqlDocumentation": {
+ "schema": {
+ "displayName": "sample-graphql",
+ "file": "./specs/schema.graphql"
+ },
+ "endpointUri": "https://demo.google.com/graphql"
+ }
+ }
+]
\ No newline at end of file
diff --git a/samples/EdgeConfig/shared-pom.xml b/samples/EdgeConfig/shared-pom.xml
index 1ca96c4..7366632 100644
--- a/samples/EdgeConfig/shared-pom.xml
+++ b/samples/EdgeConfig/shared-pom.xml
@@ -26,7 +26,7 @@
com.apigee.edge.config
apigee-config-maven-plugin
- 2.5.0
+ 2.6.0-SNAPSHOT
create-config-targetserver
@@ -112,6 +112,20 @@
importKeys
+
+ create-portal-categories
+ install
+
+ apicategories
+
+
+
+ create-portal-docs
+ install
+
+ apidocs
+
+
@@ -127,6 +141,7 @@
${env}
oauth
${bearer}
+ ${siteId}
${file}
@@ -140,6 +155,7 @@
${env}
oauth
${bearer}
+ ${siteId}
${file}
diff --git a/samples/EdgeConfig/specs/openapi.yaml b/samples/EdgeConfig/specs/openapi.yaml
new file mode 100644
index 0000000..ab73985
--- /dev/null
+++ b/samples/EdgeConfig/specs/openapi.yaml
@@ -0,0 +1,144 @@
+openapi: 3.0.0
+info:
+ description: OpenAPI Specification for the Apigee mock target service endpoint.
+ version: 1.0.0
+ title: Mock Target API
+paths:
+ /:
+ get:
+ summary: View personalized greeting
+ operationId: View a personalized greeting
+ description: View a personalized greeting for the specified or guest user.
+ parameters:
+ - name: user
+ in: query
+ description: Your user name.
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success
+ /help:
+ get:
+ summary: Get help
+ operationId: Get help
+ description: View help information about available resources in HTML format.
+ responses:
+ "200":
+ description: Success
+ /user:
+ get:
+ summary: View personalized greeting
+ operationId: View personalized greeting
+ description: View a personalized greeting for the specified or guest user.
+ parameters:
+ - name: user
+ in: query
+ description: Your user name.
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success
+ /iloveapis:
+ get:
+ summary: View API affirmation
+ operationId: View API affirmation
+ description: View API affirmation in HTML format.
+ responses:
+ "200":
+ description: Success
+ /ip:
+ get:
+ summary: View IP address
+ operationId: View IP address
+ description: View the IP address of the client in JSON format.
+ responses:
+ "200":
+ description: Success
+ /xml:
+ get:
+ summary: View XML response
+ operationId: View XML response
+ description: View a sample response in XML format.
+ responses:
+ "200":
+ description: Success
+ /json:
+ get:
+ summary: View JSON response
+ operationId: View JSON response
+ description: View a sample response in JSON format.
+ responses:
+ "200":
+ description: Success
+ /echo:
+ get:
+ summary: View request headers and body
+ operationId: View request headers and body
+ description: View the request headers and body in JSON format.
+ responses:
+ "200":
+ description: Success
+ post:
+ summary: Send request and view request headers and body
+ operationId: Send request and view request headers and body
+ description: "Send a request and view the resulting request headers and body in JSON
+ format.
+The request payload can be specified using one of the
+ following formats: application/json, application/x-www-form-urlencoded,
+ or application/xml."
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/request-body"
+ description: Request payload in application/json,
+ application/x-www-form-urlencoded, or application/xml format.
+ required: true
+ responses:
+ "200":
+ description: Success
+ "/statuscode/{code}":
+ get:
+ summary: View status code and message
+ operationId: View status code and message
+ description: View status code and message for the specified value.
+ parameters:
+ - name: code
+ in: path
+ description: HTTP status code.
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Success
+ /auth:
+ get:
+ security:
+ - basicAuth: []
+ summary: Validate access using basic authentication
+ operationId: Validate access using basic authentication
+ description: Validate access using basic authentication.
+ responses:
+ "200":
+ description: Success
+servers:
+ - url: http://mocktarget.apigee.net
+ - url: https://mocktarget.apigee.net
+components:
+ securitySchemes:
+ basicAuth:
+ type: http
+ description: HTTP Basic Authentication.
+ scheme: basic
+ schemas:
+ request-body:
+ properties:
+ replace-me:
+ type: object
+ description: Replace with request payload in application/json,
+ application/x-www-form-urlencoded, or application/xml format.
\ No newline at end of file
diff --git a/samples/EdgeConfig/specs/schema.graphql b/samples/EdgeConfig/specs/schema.graphql
new file mode 100644
index 0000000..96da1bb
--- /dev/null
+++ b/samples/EdgeConfig/specs/schema.graphql
@@ -0,0 +1,12 @@
+type Query {
+ greeting:String
+ students:[Student]
+}
+
+type Student {
+ id:ID!
+ firstName:String
+ lastName:String
+ password:String
+ collegeId:String
+}
\ No newline at end of file
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/APICategoriesMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/APICategoriesMojo.java
new file mode 100644
index 0000000..46177ef
--- /dev/null
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/APICategoriesMojo.java
@@ -0,0 +1,276 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.apigee.edge.config.mavenplugin;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import com.apigee.edge.config.rest.RestUtil;
+import com.apigee.edge.config.utils.ServerProfile;
+import com.google.api.client.http.HttpResponse;
+import com.google.api.client.http.HttpResponseException;
+
+/** ¡¡
+ * Goal to create API Categories in Apigee Portal
+ * scope: org
+ *
+ * @author ssvaidyanathan
+ * @goal apicategories
+ * @phase install
+ */
+
+public class APICategoriesMojo extends GatewayAbstractMojo
+{
+ static Logger logger = LogManager.getLogger(APICategoriesMojo.class);
+ public static final String ____ATTENTION_MARKER____ =
+ "************************************************************************";
+
+ enum OPTIONS {
+ none, create, update, delete, sync
+ }
+
+ OPTIONS buildOption = OPTIONS.none;
+
+ private ServerProfile serverProfile;
+
+ public APICategoriesMojo() {
+ super();
+
+ }
+
+ public void init() throws MojoExecutionException, MojoFailureException {
+ try {
+ logger.info(____ATTENTION_MARKER____);
+ logger.info("Apigee Portal API Categories");
+ logger.info(____ATTENTION_MARKER____);
+
+ String options="";
+ serverProfile = super.getProfile();
+
+ options = super.getOptions();
+ if (options != null) {
+ buildOption = OPTIONS.valueOf(options);
+ }
+ logger.debug("Build option " + buildOption.name());
+ logger.debug("Base dir " + super.getBaseDirectoryPath());
+ if (serverProfile.getPortalSiteId() == null) {
+ throw new MojoExecutionException(
+ "Portal Site ID not found in profile");
+ }
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException("Invalid apigee.option provided");
+ } catch (RuntimeException e) {
+ throw e;
+ }
+
+ }
+
+ protected void doUpdate(List categories)
+ throws MojoFailureException {
+ try {
+ Map existingCategories = null;
+ if (buildOption != OPTIONS.update &&
+ buildOption != OPTIONS.create &&
+ buildOption != OPTIONS.delete &&
+ buildOption != OPTIONS.sync) {
+ return;
+ }
+ logger.info("Retrieving existing API Categories - " +
+ serverProfile.getEnvironment());
+ existingCategories = getCategories(serverProfile);
+
+ for (String category : categories) {
+ if (existingCategories != null && existingCategories.keySet()!=null
+ && existingCategories.keySet().contains(category)) {
+ switch (buildOption) {
+ case update:
+ logger.info("API Category \"" + category +
+ "\" already exists. Skipping.");
+ break;
+ case create:
+ logger.info("API Category \"" + category +
+ "\" already exists. Skipping.");
+ break;
+ case delete:
+ logger.info("API Category \"" + category +
+ "\" already exists. Deleting.");
+ deleteAPICategory(serverProfile, existingCategories.get(category));
+ break;
+ case sync:
+ logger.info("API Category \"" + category +
+ "\" already exists. Deleting and recreating.");
+ deleteAPICategory(serverProfile, existingCategories.get(category));
+ logger.info("Creating API Category - " + category);
+ createAPICategory(serverProfile, category);
+ break;
+ }
+ } else {
+ switch (buildOption) {
+ case create:
+ case sync:
+ case update:
+ logger.info("Creating API Category - " + category);
+ createAPICategory(serverProfile, category);
+ break;
+ case delete:
+ logger.info("API Category \"" + category +
+ "\" does not exist. Skipping.");
+ break;
+ }
+ }
+ }
+
+ } catch (IOException e) {
+ throw new MojoFailureException("Apigee network call error " +
+ e.getMessage());
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ /**
+ * Entry point for the mojo.
+ */
+ public void execute() throws MojoExecutionException, MojoFailureException {
+
+ if (super.isSkip()) {
+ logger.info("Skipping");
+ return;
+ }
+
+ Logger logger = LogManager.getLogger(APICategoriesMojo.class);
+
+ try {
+
+ init();
+
+ if (buildOption == OPTIONS.none) {
+ logger.info("Skipping API Categories (default action)");
+ return;
+ }
+
+ if (serverProfile.getEnvironment() == null) {
+ throw new MojoExecutionException(
+ "Apigee environment not found in profile");
+ }
+
+ List categories = getOrgConfig(logger, "apiCategories");
+ if (categories == null || categories.size() == 0) {
+ logger.info("No API Categories found.");
+ return;
+ }
+ doUpdate(categories);
+
+ } catch (MojoFailureException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ /***************************************************************************
+ * REST call wrappers
+ **/
+ public static String createAPICategory(ServerProfile profile, String category)
+ throws IOException {
+ RestUtil restUtil = new RestUtil(profile);
+ String payload = "{\"name\": \""+category+"\"}";
+ HttpResponse response = restUtil.createOrgConfig(profile,
+ "sites/"+profile.getPortalSiteId()+"/apicategories",
+ payload);
+ try {
+
+ logger.info("Response " + response.getContentType() + "\n" +
+ response.parseAsString());
+ if (response.isSuccessStatusCode())
+ logger.info("Create Success.");
+
+ } catch (HttpResponseException e) {
+ logger.error("API Category create error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return "";
+ }
+
+ public static String deleteAPICategory(ServerProfile profile,
+ String categoryId)
+ throws IOException {
+ RestUtil restUtil = new RestUtil(profile);
+ HttpResponse response = restUtil.deleteOrgConfig(profile,
+ "sites/"+profile.getPortalSiteId()+"/apicategories",
+ categoryId);
+ try {
+
+ logger.info("Response " + response.getContentType() + "\n" +
+ response.parseAsString());
+ if (response.isSuccessStatusCode())
+ logger.info("Delete Success.");
+
+ } catch (HttpResponseException e) {
+ logger.error("API Category delete error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return "";
+ }
+
+ public static Map getCategories(ServerProfile profile)
+ throws IOException {
+ Map categoryMap = new HashMap();
+ RestUtil restUtil = new RestUtil(profile);
+ HttpResponse response = restUtil.getOrgConfig(profile, "sites/"+profile.getPortalSiteId()+"/apicategories");
+ if(response == null) return categoryMap;
+ JSONArray categories = null;
+ try {
+ logger.debug("output " + response.getContentType());
+ String payload = response.parseAsString();
+ logger.debug(payload);
+
+ JSONParser parser = new JSONParser();
+ JSONObject obj = (JSONObject)parser.parse(payload);
+ categories = (JSONArray)obj.get("data");
+ for (int i = 0; categories != null && i < categories.size(); i++) {
+ JSONObject a = (JSONObject) categories.get(i);
+ categoryMap.put((String)a.get("name"), (String)a.get("id"));
+ }
+ } catch (ParseException pe){
+ logger.error("Get Categories parse error " + pe.getMessage());
+ throw new IOException(pe.getMessage());
+ } catch (HttpResponseException e) {
+ logger.error("Get Categories error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return categoryMap;
+ }
+
+}
+
+
+
+
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/APIDocsMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/APIDocsMojo.java
new file mode 100644
index 0000000..8a837fa
--- /dev/null
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/APIDocsMojo.java
@@ -0,0 +1,466 @@
+/**
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.apigee.edge.config.mavenplugin;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import com.apigee.edge.config.rest.RestUtil;
+import com.apigee.edge.config.utils.ServerProfile;
+import com.google.api.client.http.HttpResponse;
+import com.google.api.client.http.HttpResponseException;
+import com.google.api.client.util.Key;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+
+/** ¡¡
+ * Goal to create API Docs in Apigee Portal
+ * scope: org
+ *
+ * @author ssvaidyanathan
+ * @goal apidocs
+ * @phase install
+ */
+
+public class APIDocsMojo extends GatewayAbstractMojo
+{
+ static Logger logger = LogManager.getLogger(APIDocsMojo.class);
+ public static final String ____ATTENTION_MARKER____ =
+ "************************************************************************";
+
+ enum OPTIONS {
+ none, create, update, delete, sync
+ }
+
+ OPTIONS buildOption = OPTIONS.none;
+
+ private ServerProfile serverProfile;
+
+ public APIDocsMojo() {
+ super();
+
+ }
+
+ public static class APIDoc {
+ @Key
+ public String title;
+ @Key
+ public List categories;
+ }
+
+ protected String getAPIDocName(String payload) throws MojoFailureException {
+ Gson gson = new Gson();
+ try {
+ APIDoc apiDoc = gson.fromJson(payload, APIDoc.class);
+ return apiDoc.title;
+ } catch (JsonParseException e) {
+ throw new MojoFailureException(e.getMessage());
+ }
+ }
+
+ protected String updatePayloadWithCategoryId(String payload, ServerProfile profile) throws MojoFailureException, IOException {
+ Gson gson = new Gson();
+ try {
+ APIDoc apiDoc = gson.fromJson(payload, APIDoc.class);
+ List categories = apiDoc.categories;
+ if(categories!=null && categories.size()>0) {
+ //Fetch existing categories and its id from portal
+ Map existingCategoryMap = getCategories(profile);
+ if(existingCategoryMap != null && existingCategoryMap.size()>0) {
+ JsonArray categoryIds = new JsonArray();
+ for (String category : categories) {
+ if(existingCategoryMap.get(category)!=null) {
+ JsonPrimitive id = new JsonPrimitive(existingCategoryMap.get(category));
+ categoryIds.add(id);
+ }
+ }
+ JsonParser parser = new JsonParser();
+ JsonElement jsonElement = parser.parse(payload);
+ JsonObject apiDocJsonObj = jsonElement.getAsJsonObject();
+ apiDocJsonObj.add("categoryIds", categoryIds);
+ apiDocJsonObj.remove("categories"); //remove the categories
+ return apiDocJsonObj.toString();
+ }
+ }
+ } catch (JsonParseException e) {
+ throw new MojoFailureException(e.getMessage());
+ }
+ return payload;
+ }
+
+
+ public void init() throws MojoExecutionException, MojoFailureException {
+ try {
+ logger.info(____ATTENTION_MARKER____);
+ logger.info("Apigee Portal API Docs");
+ logger.info(____ATTENTION_MARKER____);
+
+ String options="";
+ serverProfile = super.getProfile();
+
+ options = super.getOptions();
+ if (options != null) {
+ buildOption = OPTIONS.valueOf(options);
+ }
+ logger.debug("Build option " + buildOption.name());
+ logger.debug("Base dir " + super.getBaseDirectoryPath());
+ if (serverProfile.getPortalSiteId() == null) {
+ throw new MojoExecutionException(
+ "Portal Site ID not found in profile");
+ }
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException("Invalid apigee.option provided");
+ } catch (RuntimeException e) {
+ throw e;
+ }
+
+ }
+
+ protected void doUpdate(List apiDocs)
+ throws MojoFailureException {
+ try {
+ Map existingDocs = null;
+ if (buildOption != OPTIONS.update &&
+ buildOption != OPTIONS.create &&
+ buildOption != OPTIONS.delete &&
+ buildOption != OPTIONS.sync) {
+ return;
+ }
+ logger.info("Retrieving existing API Docs - " +
+ serverProfile.getEnvironment());
+ existingDocs = getAPIDocs(serverProfile);
+
+ for (String apiDoc : apiDocs) {
+ //update category with categoryId
+ apiDoc = updatePayloadWithCategoryId(apiDoc, serverProfile);
+ logger.debug("updated doc: "+ apiDoc);
+ String apiDocName = getAPIDocName(apiDoc);
+ if (apiDocName == null) {
+ throw new IllegalArgumentException(
+ "API Doc does not have a title.\n" + apiDoc + "\n");
+ }
+ if (existingDocs != null && existingDocs.keySet()!=null
+ && existingDocs.keySet().contains(apiDocName)) {
+ switch (buildOption) {
+ case update:
+ logger.info("Updating API Doc - " + apiDocName);
+ updateAPIDoc(serverProfile, existingDocs.get(apiDocName), apiDoc);
+ createAPIDocSpec(serverProfile, existingDocs.get(apiDocName), apiDoc);
+ break;
+ case create:
+ logger.info("API Doc \"" + apiDocName +
+ "\" already exists. Skipping.");
+ break;
+ case delete:
+ logger.info("API Doc \"" + apiDocName +
+ "\" already exists. Deleting.");
+ deleteAPIDoc(serverProfile, existingDocs.get(apiDocName));
+ break;
+ case sync:
+ logger.info("API Doc \"" + apiDocName +
+ "\" already exists. Deleting and recreating.");
+ deleteAPIDoc(serverProfile, existingDocs.get(apiDocName));
+ logger.info("Creating API Doc - " + apiDoc);
+ String apiDocId = createAPIDoc(serverProfile, apiDoc);
+ createAPIDocSpec(serverProfile, apiDocId, apiDoc);
+ break;
+ }
+ } else {
+ switch (buildOption) {
+ case create:
+ case sync:
+ case update:
+ logger.info("Creating API Doc - " + apiDocName);
+ String apiDocId = createAPIDoc(serverProfile, apiDoc);
+ createAPIDocSpec(serverProfile, apiDocId, apiDoc);
+ break;
+ case delete:
+ logger.info("API Doc \"" + apiDocName +
+ "\" does not exist. Skipping.");
+ break;
+ }
+ }
+ }
+
+ } catch (IOException e) {
+ throw new MojoFailureException("Apigee network call error " +
+ e.getMessage());
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ /**
+ * Entry point for the mojo.
+ */
+ public void execute() throws MojoExecutionException, MojoFailureException {
+
+ if (super.isSkip()) {
+ logger.info("Skipping");
+ return;
+ }
+
+ Logger logger = LogManager.getLogger(APIDocsMojo.class);
+
+ try {
+
+ init();
+
+ if (buildOption == OPTIONS.none) {
+ logger.info("Skipping API Docs (default action)");
+ return;
+ }
+
+ if (serverProfile.getEnvironment() == null) {
+ throw new MojoExecutionException(
+ "Apigee environment not found in profile");
+ }
+
+ List apiDocs = getOrgConfig(logger, "apiDocs");
+ if (apiDocs == null || apiDocs.size() == 0) {
+ logger.info("No API Docs found.");
+ return;
+ }
+
+ doUpdate(apiDocs);
+
+ } catch (MojoFailureException e) {
+ throw e;
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ /***************************************************************************
+ * REST call wrappers
+ **/
+ public static String createAPIDoc(ServerProfile profile, String apiDocPayload)
+ throws IOException {
+ RestUtil restUtil = new RestUtil(profile);
+ try {
+ JsonElement jsonObj= new Gson().fromJson(apiDocPayload, JsonElement.class);
+ jsonObj.getAsJsonObject().remove("oasDocumentation");
+ jsonObj.getAsJsonObject().remove("graphqlDocumentation");
+ HttpResponse response = restUtil.createOrgConfig(profile,
+ "sites/"+profile.getPortalSiteId()+"/apidocs",
+ jsonObj.toString());
+ String responseString = response.parseAsString();
+ logger.info("Response " + response.getContentType() + "\n" + responseString);
+ if (response.isSuccessStatusCode()) {
+ logger.info("Create Success.");
+ JsonElement respObj= new Gson().fromJson(responseString, JsonElement.class);
+ String docId = respObj.getAsJsonObject().get("data").getAsJsonObject().get("id").getAsString();
+ return docId;
+ }
+ } catch (HttpResponseException e) {
+ logger.error("API Doc create error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+ return "";
+ }
+
+ public static String createAPIDocSpec(ServerProfile profile, String apiDocId, String apiDocPayload)
+ throws IOException {
+ RestUtil restUtil = new RestUtil(profile);
+ try {
+ logger.info("API Documentation");
+ String specPayload = updatePayloadWithSpecContents(apiDocPayload);
+ HttpResponse response = restUtil.patchOrgConfig(profile,
+ "sites/"+profile.getPortalSiteId()+"/apidocs/"+apiDocId+"/documentation",
+ specPayload);
+
+ logger.info("Response " + response.getContentType() + "\n" +
+ response.parseAsString());
+ if (response.isSuccessStatusCode())
+ logger.info("Create Success.");
+
+ } catch (HttpResponseException e) {
+ logger.error("API Doc create error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return "";
+ }
+
+ public static String updateAPIDoc(ServerProfile profile,
+ String apiDocId,
+ String apiDocPayload)
+ throws IOException {
+ RestUtil restUtil = new RestUtil(profile);
+ try {
+ JsonElement jsonObj= new Gson().fromJson(apiDocPayload, JsonElement.class);
+ jsonObj.getAsJsonObject().remove("oasDocumentation");
+ jsonObj.getAsJsonObject().remove("graphqlDocumentation");
+ HttpResponse response = restUtil.updateOrgConfig(profile,
+ "sites/"+profile.getPortalSiteId()+"/apidocs",
+ apiDocId,
+ jsonObj.toString());
+ logger.info("Response " + response.getContentType() + "\n" +
+ response.parseAsString());
+ if (response.isSuccessStatusCode())
+ logger.info("Update Success.");
+
+ } catch (HttpResponseException e) {
+ logger.error("Target Server update error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+ return "";
+ }
+
+ public static String deleteAPIDoc(ServerProfile profile,
+ String apiDocId)
+ throws IOException {
+ RestUtil restUtil = new RestUtil(profile);
+ HttpResponse response = restUtil.deleteOrgConfig(profile,
+ "sites/"+profile.getPortalSiteId()+"/apidocs",
+ apiDocId);
+ try {
+
+ logger.info("Response " + response.getContentType() + "\n" +
+ response.parseAsString());
+ if (response.isSuccessStatusCode())
+ logger.info("Delete Success.");
+
+ } catch (HttpResponseException e) {
+ logger.error("API Doc delete error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return "";
+ }
+
+ public static Map getAPIDocs(ServerProfile profile)
+ throws IOException {
+ Map apiDocMap = new HashMap();
+ RestUtil restUtil = new RestUtil(profile);
+ HttpResponse response = restUtil.getOrgConfig(profile, "sites/"+profile.getPortalSiteId()+"/apidocs?pageSize=100");
+ if(response == null) return apiDocMap;
+ JSONArray apiDocs = null;
+ try {
+ logger.debug("output " + response.getContentType());
+ String payload = response.parseAsString();
+ logger.debug(payload);
+
+ JSONParser parser = new JSONParser();
+ JSONObject obj = (JSONObject)parser.parse(payload);
+ apiDocs = (JSONArray)obj.get("data");
+ for (int i = 0; apiDocs != null && i < apiDocs.size(); i++) {
+ JSONObject a = (JSONObject) apiDocs.get(i);
+ apiDocMap.put((String)a.get("title"), (String)a.get("id"));
+ }
+ } catch (ParseException pe){
+ logger.error("Get API Doc parse error " + pe.getMessage());
+ throw new IOException(pe.getMessage());
+ } catch (HttpResponseException e) {
+ logger.error("Get API Doc error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return apiDocMap;
+ }
+
+ public static Map getCategories(ServerProfile profile)
+ throws IOException {
+ Map categoryMap = new HashMap();
+ RestUtil restUtil = new RestUtil(profile);
+ HttpResponse response = restUtil.getOrgConfig(profile, "sites/"+profile.getPortalSiteId()+"/apicategories");
+ if(response == null) return categoryMap;
+ JSONArray categories = null;
+ try {
+ logger.debug("output " + response.getContentType());
+ String payload = response.parseAsString();
+ logger.debug(payload);
+
+ JSONParser parser = new JSONParser();
+ JSONObject obj = (JSONObject)parser.parse(payload);
+ categories = (JSONArray)obj.get("data");
+ for (int i = 0; categories != null && i < categories.size(); i++) {
+ JSONObject a = (JSONObject) categories.get(i);
+ categoryMap.put((String)a.get("name"), (String)a.get("id"));
+ }
+ } catch (ParseException pe){
+ logger.error("Get Categories parse error " + pe.getMessage());
+ throw new IOException(pe.getMessage());
+ } catch (HttpResponseException e) {
+ logger.error("Get Categories error " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return categoryMap;
+ }
+
+ public static String updatePayloadWithSpecContents(String payload) throws IOException {
+ Gson gson = new Gson();
+ try {
+ JsonElement jsonObj= gson.fromJson(payload, JsonElement.class);
+ JsonElement oas = jsonObj.getAsJsonObject().get("oasDocumentation");
+ if(oas!=null) {
+ JsonObject spec = oas.getAsJsonObject().get("spec").getAsJsonObject();
+ spec.addProperty("contents", fileToBase64String(spec.get("file").getAsString()));
+ spec.remove("file");
+ return "{\"oasDocumentation\":"+oas.toString()+"}";
+ }
+ JsonElement gql = jsonObj.getAsJsonObject().get("graphqlDocumentation");
+ if(gql!=null) {
+
+ JsonObject schema = gql.getAsJsonObject().get("schema").getAsJsonObject();
+ schema.addProperty("contents", fileToBase64String(schema.get("file").getAsString()));
+ schema.remove("file");
+ return "{\"graphqlDocumentation\":"+gql.toString()+"}";
+ }
+ return null;
+ } catch (JsonParseException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+
+ public static String fileToBase64String (String filePath) throws IOException {
+ byte[] byteData;
+ String base64String=null;
+ try {
+ byteData = Files.readAllBytes(Paths.get(filePath));
+ base64String = Base64.getEncoder().encodeToString(byteData);
+ } catch (IOException e) {
+ throw new IOException(e.getMessage());
+ }
+ return base64String;
+ }
+
+}
+
+
+
+
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/APIProductMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/APIProductMojo.java
index 1e20ff2..2624af1 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/APIProductMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/APIProductMojo.java
@@ -38,7 +38,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to create API Product in Apigee EDGE
+ * Goal to create API Product in Apigee
* scope: org
*
* @author madhan.sadasivam
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/AppMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/AppMojo.java
index e2517cc..a19f37b 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/AppMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/AppMojo.java
@@ -42,7 +42,7 @@
import com.google.gson.JsonParser;
/** ¡¡
- * Goal to create Apps in Apigee EDGE
+ * Goal to create Apps in Apigee
* scope: org
*
* @author madhan.sadasivam
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/DeveloperMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/DeveloperMojo.java
index dcabebc..f0f44bd 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/DeveloperMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/DeveloperMojo.java
@@ -38,7 +38,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to create Developer in Apigee EDGE
+ * Goal to create Developer in Apigee
* scope: org
*
* @author madhan.sadasivam
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/FlowHookMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/FlowHookMojo.java
index 2a826a9..2ba99ed 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/FlowHookMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/FlowHookMojo.java
@@ -37,7 +37,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to attach flow hooks in Apigee EDGE
+ * Goal to attach flow hooks in Apigee
* scope: env
*
* @author saisaran.vaidyanathan
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/GatewayAbstractMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/GatewayAbstractMojo.java
index 3bfe1e5..9f79fe4 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/GatewayAbstractMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/GatewayAbstractMojo.java
@@ -277,6 +277,12 @@ public abstract class GatewayAbstractMojo extends AbstractMojo implements Contex
*/
private String serviceAccountFilePath;
+ /**
+ * apigee portal siteId
+ * @parameter property="apigee.portal.siteId"
+ */
+ private String portalSiteId;
+
/**
* Parameter to set for DeveloperApp to ignore API Product so that new credentials are not generated for updates (https://github.com/apigee/apigee-config-maven-plugin/issues/128)
* @parameter property="apigee.app.ignoreAPIProducts" default-value="false"
@@ -335,6 +341,7 @@ public ServerProfile getProfile() {
this.buildProfile.setClientSecret(this.clientsecret);
this.buildProfile.setKvmOverride(this.kvmOverride);
this.buildProfile.setServiceAccountJSONFile(this.serviceAccountFilePath);
+ this.buildProfile.setPortalSiteId(this.portalSiteId);
this.buildProfile.setIgnoreProductsForApp(this.ignoreProductsForApp);
// process proxy for management api endpoint
@@ -674,7 +681,7 @@ public void contextualize(Context context) throws ContextException {
* Get the proxy configuration from the maven settings
*
* @param settings the maven settings
- * @param host the host name of the apigee edge endpoint
+ * @param host the host name of the apigee endpoint
*
* @return proxy or null if none was configured or the host was non-proxied
*/
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/KVMMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/KVMMojo.java
index 4117467..50015d4 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/KVMMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/KVMMojo.java
@@ -43,7 +43,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to create KVM in Apigee EDGE.
+ * Goal to create KVM in Apigee.
* scope: org, env, api
*
* @author madhan.sadasivam
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/ReferencesMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/ReferencesMojo.java
index 1b1dff2..3b30890 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/ReferencesMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/ReferencesMojo.java
@@ -37,7 +37,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to create references in Apigee EDGE.
+ * Goal to create references in Apigee.
* scope: env
*
* @author saisaran.vaidyanathan
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/ResourceFileMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/ResourceFileMojo.java
index d461939..562b61a 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/ResourceFileMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/ResourceFileMojo.java
@@ -37,7 +37,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to create Resource Files in Apigee EDGE.
+ * Goal to create Resource Files in Apigee.
* scope: env
*
* @author saisaran.vaidyanathan
diff --git a/src/main/java/com/apigee/edge/config/mavenplugin/TargetServerMojo.java b/src/main/java/com/apigee/edge/config/mavenplugin/TargetServerMojo.java
index ec6664f..d850099 100644
--- a/src/main/java/com/apigee/edge/config/mavenplugin/TargetServerMojo.java
+++ b/src/main/java/com/apigee/edge/config/mavenplugin/TargetServerMojo.java
@@ -37,7 +37,7 @@
import com.google.gson.JsonParseException;
/** ¡¡
- * Goal to create target servers in Apigee EDGE.
+ * Goal to create target servers in Apigee.
* scope: env
*
* @author madhan.sadasivam
diff --git a/src/main/java/com/apigee/edge/config/rest/RestUtil.java b/src/main/java/com/apigee/edge/config/rest/RestUtil.java
index 77939e0..b1fa3f2 100644
--- a/src/main/java/com/apigee/edge/config/rest/RestUtil.java
+++ b/src/main/java/com/apigee/edge/config/rest/RestUtil.java
@@ -509,6 +509,7 @@ public HttpResponse patchEnvConfig(ServerProfile profile,
return response;
}
+
/***************************************************************************
* Org Config - get, create, update
@@ -754,6 +755,36 @@ public HttpResponse getOrgConfig(ServerProfile profile,
return executeAPIGet(profile, importCmd);
}
+
+
+ public HttpResponse patchOrgConfig(ServerProfile profile,
+ String resource,
+ String payload)
+ throws IOException {
+
+ ByteArrayContent content = new ByteArrayContent("application/json",
+ payload.getBytes());
+
+ String importCmd = profile.getHostUrl() + "/"
+ + profile.getApi_version() + "/organizations/"
+ + profile.getOrg() + "/" + resource;
+
+ HttpRequest restRequest = APACHE_REQUEST_FACTORY.buildRequest(HttpMethods.PATCH, new GenericUrl(importCmd), content);
+ restRequest.setReadTimeout(0);
+
+ //logger.info(PrintUtil.formatRequest(restRequest));
+
+ HttpResponse response;
+ try {
+ //response = restRequest.execute();
+ response = executeAPI(profile, restRequest);
+ } catch (HttpResponseException e) {
+ logger.error("Apigee call failed " + e.getMessage());
+ throw new IOException(e.getMessage());
+ }
+
+ return response;
+ }
/***************************************************************************
* API Config - get, create, update
diff --git a/src/main/java/com/apigee/edge/config/utils/ConfigReader.java b/src/main/java/com/apigee/edge/config/utils/ConfigReader.java
index a5a1b6c..dfc7fd8 100644
--- a/src/main/java/com/apigee/edge/config/utils/ConfigReader.java
+++ b/src/main/java/com/apigee/edge/config/utils/ConfigReader.java
@@ -105,7 +105,10 @@ public static List getOrgConfig(File configFile)
if (configs == null) return null;
out = new ArrayList();
- for (Object config: configs) {
+ for (Object config: configs) {
+ if(config instanceof String)
+ out.add(config);
+ else
out.add(((JSONObject)config).toJSONString());
}
}
diff --git a/src/main/java/com/apigee/edge/config/utils/ConsolidatedConfigReader.java b/src/main/java/com/apigee/edge/config/utils/ConsolidatedConfigReader.java
index 622900b..13ef82e 100644
--- a/src/main/java/com/apigee/edge/config/utils/ConsolidatedConfigReader.java
+++ b/src/main/java/com/apigee/edge/config/utils/ConsolidatedConfigReader.java
@@ -120,8 +120,11 @@ public static List getOrgConfig(File configFile,
if (configs == null) return null;
out = new ArrayList();
- for (Object config: configs) {
- out.add(((JSONObject)config).toJSONString());
+ for (Object config: configs) {
+ if(config instanceof String)
+ out.add(config);
+ else
+ out.add(((JSONObject)config).toJSONString());
}
}
catch(IOException ie) {
diff --git a/src/main/java/com/apigee/edge/config/utils/ServerProfile.java b/src/main/java/com/apigee/edge/config/utils/ServerProfile.java
index cdb49fe..6409fd5 100644
--- a/src/main/java/com/apigee/edge/config/utils/ServerProfile.java
+++ b/src/main/java/com/apigee/edge/config/utils/ServerProfile.java
@@ -56,6 +56,7 @@ public class ServerProfile {
private String authType; // Mgmt API Auth Type oauth|basic
private Boolean kvmOverride = true; //Override kvm only if true (used for update option)
private String serviceAccountJSONFile;
+ private String portalSiteId; //Apigee Integrated Portal Site ID
private Boolean ignoreProductsForApp = true; //Ignore API Product for App creation/updates so new credentials are not created
@@ -98,6 +99,14 @@ public String getServiceAccountJSONFile() {
public void setServiceAccountJSONFile(String serviceAccountJSONFile) {
this.serviceAccountJSONFile = serviceAccountJSONFile;
}
+
+ public String getPortalSiteId() {
+ return portalSiteId;
+ }
+
+ public void setPortalSiteId(String portalSiteId) {
+ this.portalSiteId = portalSiteId;
+ }
public String getHostURL() {
return hostURL;