Customizing Lifecycle states in WSO2 API Manager

WSO2 API Manageris a 100% open source API Management solution inluding support for API publishing, lifecycle management, developer portal, access control and analytics. APIs have their own life cycle which can be managed through WSO2 API Publisher while enabling many essential features for API Management, such as,

  • Create new APIs from existing versions
  • Deploy multiple versions in parallel
  • Deprecate versions to remove them from store
  • Retire them to un-deploy from gateway
  • Keeps audit of lifecycle changes
  • Supports customizing lifecycles 

The ability to customize API life cycle provides a greater flexibility to achieve various requirements. There are few extension points available for customizing the API Lifecycle. Find more details about those from the product documentation [1]. 
  • Adding new lifecycle state
  • Changing the state transition events
  • Changing the state transition execution (In each state transition, we can configure an execution logic to be run)

In this blog post, I will explain how we can add a custom life cycle state to APIM 2.1.0. 

Example scenario : Assume that in your organization, you need an intermediate state in between Created and Published, because only the admin user is allowed to publish the API. The API developers/publishers should complete the API and mark it in an intermediate state such as "Ready To Publish". Then the admin users will come to the Publisher, review the APIs in "Ready To Publish" state and mark them as "Published".

Customizing the Lifecycle(LC) configuration.

You can find the default LC configuration in APIM as follows.

1. Login to the management console.
2. Click on "Extensions" -> "Configure" -> "Lifecycles"
3. Click "View/Edit" "APILifeCycle". It will show you the default LC configuration.


Now we will be introducing a new LC state as "ReadyToPublish" which allows the transition to "Published" and "Prototyped" states by users with "admin" role. Note that, "Prototyped" is an API status which is used when early versions of APIs will be made available for the subscribers. Therefore, it is also considered as a similar state to "Published" state here.

Find the configuration part of the new state.

<state id="ReadyToPublish">
                    <datamodel>
                        <data name="transitionExecution">
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
                            </execution>
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
                            </execution>
                        </data>
   <data name="transitionPermission">
       <permission forevent="Deploy as a Prototype" roles="admin">
       <permission forevent="Publish" roles="admin">
   </permission></permission></data>
                    </datamodel>
                    <transition event="Publish" target="Published">
      <transition event="Deploy as a Prototype" target="Prototyped">
      <transition event="Demote to Created" target="Created">
                </transition></transition></transition></state>
Then "Created" status is modified such that it allows transition to "ReadyToPublish" status without any role restriction. However, admin should be able to change the status to "Published" and "Prototyped" directly from "Created".

The "transitionPermission" configuration sets the roles which are allowed to do the transitions. Here we have set it as admin.

Note that here we do not have an "transitionExecution" config for "Ready To Publish" state since, we are not performing any execution here. If you need to perform any execution when changing status from "Created" to "Ready To Publish", you can write and plug-in a LC executor for this. Refer here [2].

Find the "Created" state configuration with above mentioned modifications.


<state id="Created">
                    <datamodel>

                        <data name="checkItems">
                            <item forevent="" name="Deprecate old versions after publish the API">
                            </item>
                            <item forevent="" name="Requires re-subscription when publish the API">
                            </item>
                        </data>
   <data name="transitionExecution">
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
              </execution>
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
              </execution>
   </data>
   <data name="transitionPermission">
       <permission forevent="Deploy as a Prototype" roles="admin">
       <permission forevent="Publish" roles="admin">
   </permission></permission></data>
                    </datamodel>
                    <transition event="Ready To Publish" target="ReadyToPublish">
      <transition event="Publish" target="Published">
      <transition event="Deploy as a Prototype" target="Prototyped">               

                </transition></transition></transition></state>

Find the complete LC configuration with above mentioned changes.
<!--
 ~ Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 ~
 ~ WSO2 Inc. licenses this file to you 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.
 -->
<aspect class="org.wso2.carbon.governance.registry.extensions.aspects.DefaultLifeCycle" name="APILifeCycle">
    <configuration type="literal">
        <lifecycle>
            <scxml initialstate="Created" version="1.0" xmlns="http://www.w3.org/2005/07/scxml">

                <state id="Created">
                    <datamodel>

                        <data name="checkItems">
                            <item forevent="" name="Deprecate old versions after publish the API">
                            </item>
                            <item forevent="" name="Requires re-subscription when publish the API">
                            </item>
                        </data>
   <data name="transitionExecution">
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
              </execution>
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
              </execution>
   </data>
   <data name="transitionPermission">
       <permission forevent="Deploy as a Prototype" roles="admin">
       <permission forevent="Publish" roles="admin">
   </permission></permission></data>
                    </datamodel>
                    <transition event="Ready To Publish" target="ReadyToPublish">
      <transition event="Publish" target="Published">
      <transition event="Deploy as a Prototype" target="Prototyped">               

                </transition></transition></transition></state>

  <state id="ReadyToPublish">
                    <datamodel>
                        <data name="transitionExecution">
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
                            </execution>
       <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
                            </execution>
                        </data>
   <data name="transitionPermission">
       <permission forevent="Deploy as a Prototype" roles="admin">
       <permission forevent="Publish" roles="admin">
   </permission></permission></data>
                    </datamodel>
                    <transition event="Publish" target="Published">
      <transition event="Deploy as a Prototype" target="Prototyped">
      <transition event="Demote to Created" target="Created">
                </transition></transition></transition></state>

                <state id="Prototyped">
                    <datamodel>
                        <data name="checkItems">
                            <item forevent="" name="Deprecate old versions after publish the API">
                            </item>
                            <item forevent="" name="Requires re-subscription when publish the API">
                            </item>
                        </data>

                        <data name="transitionExecution">
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Publish">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
                            </execution>
                        </data>
                    </datamodel>
                    <transition event="Publish" target="Published">
                    <transition event="Demote to Created" target="Created">
                    <transition event="Deploy as a Prototype" target="Prototyped">
                </transition></transition></transition></state>


                <state id="Published">

                    <datamodel>

                        <data name="transitionExecution">
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Block">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deprecate">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Demote to Created">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deploy as a Prototype">
                            </execution>

                        </data>
                    </datamodel>
                    <transition event="Block" target="Blocked">
                    <transition event="Deploy as a Prototype" target="Prototyped">
                    <transition event="Demote to Created" target="Created">
                    <transition event="Deprecate" target="Deprecated">
                    <transition event="Publish" target="Published">
                </transition></transition></transition></transition></transition></state>

                <state id="Blocked">
                    <datamodel>
                        <data name="transitionExecution">
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Re-Publish">
                            </execution>
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Deprecate">
                            </execution>
                        </data>
                    </datamodel>
                    <transition event="Deprecate" target="Deprecated">
                    <transition event="Re-Publish" target="Published">
                </transition></transition></state>

                <state id="Deprecated">
                    <datamodel>
                        <data name="transitionExecution">
                            <execution class="org.wso2.carbon.apimgt.impl.executors.APIExecutor" forevent="Retire">
                            </execution>
                        </data>
                    </datamodel>
                    <transition event="Retire" target="Retired">
                </transition></state>

                <state id="Retired">
                </state>
            </scxml>
        </lifecycle>
    </configuration>
</aspect>


Now add this configuration to the APIM's Lifecycle configuration through the management console and Save.

Configure the UI to show the new LC state with a preferred display name.

When you add the new LC state, it will be displayed in the Publisher UI as "ready to publish". You can change it as you prefer as below.

Go to <AM_HOME>/repository/deployment/server/jaggeryapps/publisher/site/conf/locales/jaggery/locale_default.json . Add "ready to publish": "Ready To Publish" to end of the file. Note that the key in the JSON pair should be lowercase.


Now the configuration required are completed. When a user with publish permission (no admin permissions) goes to the LC tab of an API in "Created" state, user can only change it to "Ready to Publish" state as above.

One the state is changed to  "Ready to Publish", user can then demote it to Created again. 


Now if the admin logs in and checks this API, he will be getting options to "Publish" and "Deploy as Prototype" as well.


This way, we can control who can Publish the API by role.  This is just an example scenario to explain the capabilities available in WSO2 API Manager to customize the Lifecycle states. So based on your requirements, these extension options can be used accordingly.

Thank You!

Comments

Popular posts from this blog

How to add Maven dependency from a relative path referencing a local jar

PHP-SOAP web service with out a WSDL

Manually install a maven dependency