public ApiVersionBeanDto createApiVersion(String organizationId, String apiId,
                                              NewApiVersionBean newApiVersion) throws ApiNotFoundException, NotAuthorizedException,
        InvalidVersionException, ApiVersionAlreadyExistsException {

        FieldValidator.validateVersion(newApiVersion.getVersion());

        ApiVersionBean newVersion = tryAction(() -> {
            GatewaySummaryBean gateway = getSingularGateway();

            ApiBean api = getApiFromStorage(organizationId, apiId);

            if (storage.getApiVersion(organizationId, apiId, newApiVersion.getVersion()) != null) {
                throw ExceptionFactory.apiVersionAlreadyExistsException(apiId, newApiVersion.getVersion());
            }

            return createApiVersionInternal(newApiVersion, api, gateway);
        });

        if (newApiVersion.isClone() && newApiVersion.getCloneVersion() != null) {
            try {
                ApiVersionBean cloneSource = storage.getApiVersion(organizationId, apiId, newApiVersion.getCloneVersion());
                //storage.flush();

                // Clone primary attributes of the API version unless those attributes
                // were included in the NewApiVersionBean.  In other words, information
                // sent as part of the "create version" payload take precedence over the
                // cloned attributes.
                UpdateApiVersionBean updatedApi = new UpdateApiVersionBean();
                if (newApiVersion.getEndpoint() == null) {
                    updatedApi.setEndpoint(cloneSource.getEndpoint());
                }
                if (newApiVersion.getEndpointType() == null) {
                    updatedApi.setEndpointType(cloneSource.getEndpointType());
                }
                if (newApiVersion.getEndpointContentType() == null) {
                    updatedApi.setEndpointContentType(cloneSource.getEndpointContentType());
                }
                updatedApi.setEndpointProperties(cloneSource.getEndpointProperties());
                updatedApi.setGateways(cloneSource.getGateways());
                if (newApiVersion.getPlans() == null) {
                    List<ApiPlanBean> sorted = new ArrayList<>(cloneSource.getPlans());
                    sorted.sort(Comparator.comparingInt(ApiPlanBean::getOrderIndex));
                    LinkedHashSet<UpdateApiPlanDto> plans = ApiVersionMapper.INSTANCE.toDto2(new LinkedHashSet<>(sorted));
                    updatedApi.setPlans(plans);
                }
                if (newApiVersion.getPublicAPI() == null) {
                    updatedApi.setPublicAPI(cloneSource.isPublicAPI());
                }
                if (newApiVersion.getParsePayload() == null) {
                    updatedApi.setParsePayload(cloneSource.isParsePayload());
                }
                if (newApiVersion.getExtendedDescription() == null) {
                    updatedApi.setExtendedDescription(cloneSource.getExtendedDescription());
                }

                ApiVersionBean updated = updateApiVersion(newVersion, updatedApi);

                if (newApiVersion.getDefinitionUrl() == null) {
                    // Clone the API definition document
                    InputStream definition = null;
                    try {
                        definition = getApiDefinition(organizationId, apiId, newApiVersion.getCloneVersion()).getDefinition();
                        setApiDefinition(organizationId, apiId, updated.getVersion(),
                            cloneSource.getDefinitionType(), definition, cloneSource.getDefinitionUrl());
                    } catch (ApiDefinitionNotFoundException svnfe) {
                        // This is ok - it just means the API doesn't have one, so do nothing.
                    } catch (Exception sdnfe) {
                        LOGGER.error("Unable to create response", sdnfe); //$NON-NLS-1$
                    } finally {
                        IOUtils.closeQuietly(definition);
                    }
                }

                // Clone all API policies
                List<PolicySummaryBean> policies = listApiPolicies(organizationId, apiId, newApiVersion.getCloneVersion());
                for (PolicySummaryBean policySummary : policies) {
                    PolicyBean policy = getApiPolicy(organizationId, apiId, newApiVersion.getCloneVersion(), policySummary.getId());
                    NewPolicyBean npb = new NewPolicyBean();
                    npb.setDefinitionId(policy.getDefinition().getId());
                    npb.setConfiguration(policy.getConfiguration());
                    createApiPolicy(organizationId, apiId, updated.getVersion(), npb);
                }
            } catch (Exception e) {
                e.printStackTrace();
                // TODO(msavy): is this actually doing anything useful? Should we just remove this?
                // TODO it's ok if the clone fails - we did our best
                if (e != null) {
                    Throwable t = e;
                    e = (Exception) t;
                }
            }
        }

        return apiVersionMapper.toDto(newVersion);
    }
Gets the API from storage
@param organizationId the organizationId
@param apiId the apiId
@return the api
@throws ApiNotFoundException if the API is not found
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java