diff options
Diffstat (limited to 'dcaedt_catalog/asdc/src/main')
25 files changed, 2799 insertions, 0 deletions
diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDC.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDC.java new file mode 100644 index 0000000..66afab1 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDC.java @@ -0,0 +1,1101 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import java.net.URI; +import java.net.URISyntaxException; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; + +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.Collections; + +import java.util.function.UnaryOperator; + +import javax.annotation.PostConstruct; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.enums.ArtifactGroupType; +import org.onap.sdc.dcae.enums.ArtifactType; +import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed; +import org.springframework.http.MediaType; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpRequest; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpEntity; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.client.AsyncClientHttpRequestExecution; +import org.springframework.http.client.AsyncClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.AsyncRestTemplate; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.http.converter.HttpMessageConverter; + +import org.springframework.util.Base64Utils; +//import org.springframework.util.DigestUtils; +import org.apache.commons.codec.digest.DigestUtils; + +import org.springframework.stereotype.Component; +import org.springframework.context.annotation.Scope; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.beans.factory.annotation.Autowired; + +import org.springframework.util.concurrent.ListenableFuture; +import org.springframework.util.concurrent.ListenableFutureCallback; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; + +import org.json.JSONObject; +import org.onap.sdc.dcae.catalog.commons.Action; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.Futures; +import org.onap.sdc.dcae.catalog.commons.JSONHttpMessageConverter; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.composition.util.SystemProperties; +import org.json.JSONArray; + +import org.apache.commons.cli.BasicParser; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + + +@Component("asdc") +@Scope("singleton") +//@ConfigurationProperties(prefix="asdc") +public class ASDC { + + public static enum AssetType { + resource, + service, + product + } + +// public static enum ArtifactType { +// DCAE_TOSCA, +// DCAE_JSON, +// DCAE_POLICY, +// DCAE_DOC, +// DCAE_EVENT, +// DCAE_INVENTORY_TOSCA, +// DCAE_INVENTORY_JSON, +// DCAE_INVENTORY_POLICY, +// DCAE_INVENTORY_DOC, +// DCAE_INVENTORY_BLUEPRINT, +// DCAE_INVENTORY_EVENT, +// HEAT, +// HEAT_VOL, +// HEAT_NET, +// HEAT_NESTED, +// HEAT_ARTIFACT, +// HEAT_ENV, +// OTHER +// } + +// public static enum ArtifactGroupType { +// DEPLOYMENT, +// INFORMATIONAL +// } + + public static enum LifecycleState { + Checkin, + Checkout, + Certify, + undocheckout + } + + +// @Retention(RetentionPolicy.RUNTIME) +// @Target(ElementType.METHOD) +// public @interface Mandatory { +// } + + protected static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + protected static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @Autowired + private SystemProperties systemProperties; + + private URI rootUri; + private String rootPath = "/sdc/v1/catalog/"; + private String user, + passwd; + private String instanceId; + + + public void setUri(URI theUri) { + //theUri = URI.create(systemProperties.getProperties().getProperty(SystemProperties.ASDC_CATALOG_URL)); + String userInfo = theUri.getUserInfo(); + if (userInfo != null) { + String[] userInfoParts = userInfo.split(":"); + setUser(userInfoParts[0]); + if (userInfoParts.length > 1) + setPassword(userInfoParts[1]); + } + String fragment = theUri.getFragment(); + if (fragment == null) + throw new IllegalArgumentException("The URI must contain a fragment specification, to be used as ASDC instance id"); + setInstanceId(fragment); + + try { + this.rootUri = new URI(theUri.getScheme(), null, theUri.getHost(), theUri.getPort(), theUri.getPath(), theUri.getQuery(), null); + } + catch (URISyntaxException urix) { + throw new IllegalArgumentException("Invalid uri", urix); + } + } + + public URI getUri() { + return this.rootUri; + } + + public void setUser(String theUser) { + this.user = theUser; + } + + public String getUser() { + return this.user; + } + + public void setPassword(String thePassword) { + this.passwd = thePassword; + } + + public String getPassword() { + return this.passwd; + } + + public void setInstanceId(String theId) { + this.instanceId = theId; + } + + public String getInstanceId() { + return this.instanceId; + } + + public void setRootPath(String thePath) { + this.rootPath = systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_ROOTPATH); + } + + public String getRootPath() { + return systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_ROOTPATH); + } + + @Scheduled(fixedRateString = "${beans.context.scripts.updateCheckFrequency?:60000}") + public void checkForUpdates() { + } + + @PostConstruct + public void initASDC() { + } + + public <T> Future<T> getResources(Class<T> theType) { + return getAssets(AssetType.resource, theType); + } + + public Future<JSONArray> getResources() { + return getAssets(AssetType.resource, JSONArray.class); + } + + public <T> Future<T> getResources(Class<T> theType, String theCategory, String theSubCategory) { + return getAssets(AssetType.resource, theType, theCategory, theSubCategory); + } + + public Future<JSONArray> getResources(String category, String subCategory, String resourceType) { + return getAssets(AssetType.resource, JSONArray.class, category, subCategory, resourceType); + } + + public <T> Future<T> getServices(Class<T> theType) { + return getAssets(AssetType.service, theType); + } + + public Future<JSONArray> getServices() { + return getAssets(AssetType.service, JSONArray.class); + } + + public <T> Future<T> getServices(Class<T> theType, String theCategory, String theSubCategory) { + return getAssets(AssetType.service, theType, theCategory, theSubCategory); + } + + public Future<JSONArray> getServices(String theCategory, String theSubCategory) { + return getAssets(AssetType.service, JSONArray.class, theCategory, theSubCategory); + } + + public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType) { + return fetch(refAssets(theAssetType), theType); + } + + public <T> Action<T> getAssetsAction(AssetType theAssetType, Class<T> theType) { + return (() -> fetch(refAssets(theAssetType), theType)); + } + + public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType, + String theCategory, String theSubCategory) { + return getAssets(theAssetType, theType, theCategory, theSubCategory, null); + } + + public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType, + String theCategory, String theSubCategory, String theResourceType) { + return fetch(refAssets(theAssetType) + filter(theCategory, theSubCategory, theResourceType), theType); + } + + public <T> Action<T> getAssetsAction(AssetType theAssetType, Class<T> theType, + String theCategory, String theSubCategory, String theResourceType) { + return (() -> fetch(refAssets(theAssetType) + filter(theCategory, theSubCategory, theResourceType), theType)); + } + + protected String refAssets(AssetType theAssetType) { + return this.rootPath + theAssetType + "s/"; + } + + private String filter(String theCategory, String theSubCategory, String theResourceType) { + StringBuilder filter = null; + if (theCategory != null) { + filter = new StringBuilder(); + filter.append("?category=") + .append(theCategory); + if (theSubCategory != null) { + filter.append("&subCategory=") + .append(theSubCategory); + if (theResourceType != null) { + filter.append("&resourceType=") + .append(theResourceType); + } + } + } + return filter == null ? "" : filter.toString(); + } + + protected String refAsset(AssetType theAssetType, UUID theId) { + return this.rootPath + theAssetType + "s/" + theId; + } + + public <T> Future<T> getResource(UUID theId, Class<T> theType) { + return getAsset(AssetType.resource, theId, theType); + } + + public Future<JSONObject> getResource(UUID theId) { + return getAsset(AssetType.resource, theId, JSONObject.class); + } + + public Future<ResourceDetailed> getSDCResource(UUID theId) { + return getAsset(AssetType.resource, theId, ResourceDetailed.class); + } + + + public <T> Future<T> getService(UUID theId, Class<T> theType) { + return getAsset(AssetType.service, theId, theType); + } + + public Future<JSONObject> getService(UUID theId) { + return getAsset(AssetType.service, theId, JSONObject.class); + } + + public <T> Future<T> getAsset(AssetType theAssetType, UUID theId, Class<T> theType) { + return fetch(refAsset(theAssetType, theId) + "/metadata", theType); + } + + public <T> Action<T> getAssetAction(AssetType theAssetType, UUID theId, Class<T> theType) { + return (() -> fetch(refAsset(theAssetType, theId) + "/metadata", theType)); + } + + public Future<byte[]> getResourceArchive(UUID theId) { + return getAssetArchive(AssetType.resource, theId); + } + + public Future<byte[]> getServiceArchive(UUID theId) { + return getAssetArchive(AssetType.service, theId); + } + + public Future<byte[]> getAssetArchive(AssetType theAssetType, UUID theId) { + return fetch(refAsset(theAssetType, theId) + "/toscaModel", byte[].class); + } + + public Action<byte[]> getAssetArchiveAction(AssetType theAssetType, UUID theId) { + return (() -> fetch(refAsset(theAssetType, theId) + "/toscaModel", byte[].class)); + } + + public Future<JSONObject> checkinResource(UUID theId, String theUser, String theMessage) { + return cycleAsset(AssetType.resource, theId, LifecycleState.Checkin, theUser, theMessage); + } + + public Future<JSONObject> checkinService(UUID theId, String theUser, String theMessage) { + return cycleAsset(AssetType.service, theId, LifecycleState.Checkin, theUser, theMessage); + } + + public Future<JSONObject> checkoutResource(UUID theId, String theUser, String theMessage) { + return cycleAsset(AssetType.resource, theId, LifecycleState.Checkout, theUser, theMessage); + } + + public Future<JSONObject> checkoutService(UUID theId, String theUser, String theMessage) { + return cycleAsset(AssetType.service, theId, LifecycleState.Checkout, theUser, theMessage); + } + + public Future<JSONObject> certifyResource(UUID theId, String theUser, String theMessage) { + return cycleAsset(AssetType.resource, theId, LifecycleState.Certify, theUser, theMessage); + } + + public Future<JSONObject> certifyService(UUID theId, String theUser, String theMessage) { + return cycleAsset(AssetType.service, theId, LifecycleState.Certify, theUser, theMessage); + } + + /* Normally theMessage is mandatory (and we'd use put instead of putOpt) but .. not so for undocheckout .. + */ + public Future<JSONObject> cycleAsset(AssetType theAssetType, UUID theId, LifecycleState theState, + String theUser, String theMessage) { + return post(refAsset(theAssetType, theId) + "/lifecycleState/" + theState, + (headers) -> prepareHeaders(headers) + .header("USER_ID", theUser), + new JSONObject().putOpt("userRemarks", theMessage)); + } + + protected String refAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theAssetInstance, UUID theArtifactId) { + return refAsset(theAssetType, theAssetId) + "/resourceInstances/" + theAssetInstance + "/artifacts" + (theArtifactId == null ? "" : ("/" + theArtifactId)); + } + + protected String refAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId) { + return refAsset(theAssetType, theAssetId) + "/artifacts" + (theArtifactId == null ? "" : ("/" + theArtifactId)); + } + + public <T> Future<T> getResourceArtifact(UUID theAssetId, UUID theArtifactId, Class<T> theType) { + return getAssetArtifact(AssetType.resource, theAssetId, theArtifactId, theType); + } + + public <T> Future<T> getServiceArtifact(UUID theAssetId, UUID theArtifactId, Class<T> theType) { + return getAssetArtifact(AssetType.service, theAssetId, theArtifactId, theType); + } + + public <T> Future<T> getResourceInstanceArtifact(UUID theAssetId, UUID theArtifactId, String theInstance, Class<T> theType) { + return getAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactId, theType); + } + + public <T> Future<T> getServiceInstanceArtifact(UUID theAssetId, UUID theArtifactId, String theInstance, Class<T> theType) { + return getAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactId, theType); + } + + public <T> Future<T> getAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId, Class<T> theType) { + return fetch(refAssetArtifact(theAssetType, theAssetId, theArtifactId), theType); + } + + public <T> Action<T> getAssetArtifactAction(AssetType theAssetType, UUID theAssetId, UUID theArtifactId, Class<T> theType) { + return (() -> fetch(refAssetArtifact(theAssetType, theAssetId, theArtifactId), theType)); + } + + public <T> Future<T> getAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId, Class<T> theType) { + return fetch(refAssetInstanceArtifact(theAssetType, theAssetId, theInstance, theArtifactId), theType); + } + + public <T> Action<T> getAssetInstanceArtifactAction(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId, Class<T> theType) { + return (() -> fetch(refAssetInstanceArtifact(theAssetType, theAssetId, theInstance, theArtifactId), theType)); + } + + public ArtifactUploadAction createResourceArtifact(UUID theAssetId) { + return createAssetArtifact(AssetType.resource, theAssetId); + } + + public ArtifactUploadAction createServiceArtifact(UUID theAssetId) { + return createAssetArtifact(AssetType.service, theAssetId); + } + + public ArtifactUploadAction createResourceInstanceArtifact(UUID theAssetId, String theInstance) { + return createAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance); + } + + public ArtifactUploadAction createServiceInstanceArtifact(UUID theAssetId, String theInstance) { + return createAssetInstanceArtifact(AssetType.service, theAssetId, theInstance); + } + + public ArtifactUploadAction createAssetArtifact(AssetType theAssetType, UUID theAssetId) { + return new ArtifactUploadAction() + .ofAsset(theAssetType, theAssetId); + } + + public ArtifactUploadAction createAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance) { + return new ArtifactUploadAction() + .ofAssetInstance(theAssetType, theAssetId, theInstance); + } + + public ArtifactUpdateAction updateResourceArtifact(UUID theAssetId, JSONObject theArtifactInfo) { + return updateAssetArtifact(AssetType.resource, theAssetId, theArtifactInfo); + } + + public ArtifactUpdateAction updateResourceInstanceArtifact(UUID theAssetId, String theInstance, JSONObject theArtifactInfo) { + return updateAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactInfo); + } + + public ArtifactUpdateAction updateServiceArtifact(UUID theAssetId, JSONObject theArtifactInfo) { + return updateAssetArtifact(AssetType.service, theAssetId, theArtifactInfo); + } + + public ArtifactUpdateAction updateServiceInstanceArtifact(UUID theAssetId, String theInstance, JSONObject theArtifactInfo) { + return updateAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactInfo); + } + + public ArtifactUpdateAction updateAssetArtifact(AssetType theAssetType, UUID theAssetId, JSONObject theArtifactInfo) { + return new ArtifactUpdateAction(theArtifactInfo) + .ofAsset(theAssetType, theAssetId); + } + + public ArtifactUpdateAction updateAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, JSONObject theArtifactInfo) { + return new ArtifactUpdateAction(theArtifactInfo) + .ofAssetInstance(theAssetType, theAssetId, theInstance); + } + + public ArtifactDeleteAction deleteResourceArtifact(UUID theAssetId, UUID theArtifactId) { + return deleteAssetArtifact(AssetType.resource, theAssetId, theArtifactId); + } + + public ArtifactDeleteAction deleteResourceInstanceArtifact(UUID theAssetId, String theInstance, UUID theArtifactId) { + return deleteAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactId); + } + + public ArtifactDeleteAction deleteServiceArtifact(UUID theAssetId, UUID theArtifactId) { + return deleteAssetArtifact(AssetType.service, theAssetId, theArtifactId); + } + + public ArtifactDeleteAction deleteServiceInstanceArtifact(UUID theAssetId, String theInstance, UUID theArtifactId) { + return deleteAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactId); + } + + public ArtifactDeleteAction deleteAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId) { + return new ArtifactDeleteAction(theArtifactId) + .ofAsset(theAssetType, theAssetId); + } + + public ArtifactDeleteAction deleteAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId) { + return new ArtifactDeleteAction(theArtifactId) + .ofAssetInstance(theAssetType, theAssetId, theInstance); + } + + + public abstract class ASDCAction<A extends ASDCAction<A, T>, T> implements Action<T> { + + protected JSONObject info; //info passed to asdc as request body + protected String operatorId; //id of the SDC user performing the action + + protected ASDCAction(JSONObject theInfo) { + this.info = theInfo; + } + + protected abstract A self(); + + protected ASDC asdc() { + return ASDC.this; + } + + protected A withInfo(JSONObject theInfo) { + merge(this.info, theInfo); + return self(); + } + + public A with(String theProperty, Object theValue) { + info.put(theProperty, theValue); + return self(); + } + + public A withOperator(String theOperator) { + this.operatorId = theOperator; + return self(); + } + + protected abstract String[] mandatoryInfoEntries(); + + protected void checkOperatorId() { + if (this.operatorId == null) { + throw new IllegalStateException("No operator id was provided"); + } + } + + protected void checkMandatoryInfo() { + for (String field: mandatoryInfoEntries()) { + if (!info.has(field)) + throw new IllegalStateException("No '" + field + "' was provided"); + } + } + + protected void checkMandatory() { + checkOperatorId(); + checkMandatoryInfo(); + } + } + + protected static final String[] artifactMandatoryEntries = new String[] {}; + + /** + * We use teh same API to operate on artifacts attached to assets or to their instances + */ + public abstract class ASDCArtifactAction<A extends ASDCArtifactAction<A>> extends ASDCAction<A, JSONObject> { + + protected AssetType assetType; + protected UUID assetId; + protected String assetInstance; + + protected ASDCArtifactAction(JSONObject theInfo) { + super(theInfo); + } + + protected A ofAsset(AssetType theAssetType, UUID theAssetId) { + this.assetType = theAssetType; + this.assetId = theAssetId; + return self(); + } + + protected A ofAssetInstance(AssetType theAssetType, UUID theAssetId, String theInstance) { + this.assetType = theAssetType; + this.assetId = theAssetId; + this.assetInstance = theInstance; + return self(); + } + + protected String normalizeInstanceName(String theName) { + return StringUtils.removePattern(theName, "[ \\.\\-]+").toLowerCase(); + } + + protected String[] mandatoryInfoEntries() { + return ASDC.this.artifactMandatoryEntries; + } + + protected String ref(UUID theArtifactId) { + return (this.assetInstance == null) ? + refAssetArtifact(this.assetType, this.assetId, theArtifactId) : + refAssetInstanceArtifact(this.assetType, this.assetId, normalizeInstanceName(this.assetInstance), theArtifactId); + } + } + + protected static final String[] uploadMandatoryEntries = new String[] { "artifactName", + "artifactType", + "artifactGroupType", + "artifactLabel", + "description", + "payloadData" }; + + public class ArtifactUploadAction extends ASDCArtifactAction<ArtifactUploadAction> { + + protected ArtifactUploadAction() { + super(new JSONObject()); + } + + protected ArtifactUploadAction self() { + return this; + } + + public ArtifactUploadAction withContent(byte[] theContent) { + return with("payloadData", Base64Utils.encodeToString(theContent)); + } + + public ArtifactUploadAction withContent(File theFile) throws IOException { + return withContent(FileUtils.readFileToByteArray(theFile)); + } + + public ArtifactUploadAction withLabel(String theLabel) { + return with("artifactLabel", theLabel); + } + + public ArtifactUploadAction withName(String theName) { + return with("artifactName", theName); + } + + public ArtifactUploadAction withDisplayName(String theName) { + return with("artifactDisplayName", theName); + } + + public ArtifactUploadAction withType(ArtifactType theType) { + return with("artifactType", theType.toString()); + } + + public ArtifactUploadAction withGroupType(ArtifactGroupType theGroupType) { + return with("artifactGroupType", theGroupType.toString()); + } + + public ArtifactUploadAction withDescription(String theDescription) { + return with("description", theDescription); + } + + protected String[] mandatoryInfoEntries() { + return ASDC.this.uploadMandatoryEntries; + } + + public Future<JSONObject> execute() { + checkMandatory(); + return ASDC.this.post(ref(null), + (headers) -> prepareHeaders(headers) + .header("USER_ID", this.operatorId), + this.info); + } + } + + protected static final String[] updateMandatoryEntries = new String[] { "artifactName", + "artifactType", + "artifactGroupType", + "artifactLabel", + "description", + "payloadData" }; + + /** + * In its current form the update relies on a previous artifact retrieval. One cannot build an update from scratch. + * The label, tye and group type must be submitted but cannot be updated + */ + public class ArtifactUpdateAction extends ASDCArtifactAction<ArtifactUpdateAction> { + + + protected ArtifactUpdateAction(JSONObject theInfo) { + super(theInfo); + } + + protected ArtifactUpdateAction self() { + return this; + } + + public ArtifactUpdateAction withContent(byte[] theContent) { + return with("payloadData", Base64Utils.encodeToString(theContent)); + } + + public ArtifactUpdateAction withContent(File theFile) throws IOException { + return withContent(FileUtils.readFileToByteArray(theFile)); + } + + public ArtifactUpdateAction withDescription(String theDescription) { + return with("description", theDescription); + } + + public ArtifactUpdateAction withName(String theName) { + return with("artifactName", theName); + } + + protected String[] mandatoryInfoEntries() { + return ASDC.this.updateMandatoryEntries; + } + + /* The json object originates (normally) from a get so it will have entries we need to cleanup */ + protected void cleanupInfoEntries() { + this.info.remove("artifactChecksum"); + this.info.remove("artifactUUID"); + this.info.remove("artifactVersion"); + this.info.remove("artifactURL"); + this.info.remove("artifactDescription"); + } + + public Future<JSONObject> execute() { + UUID artifactUUID = UUID.fromString(this.info.getString("artifactUUID")); + checkMandatory(); + cleanupInfoEntries(); + return ASDC.this.post(ref(artifactUUID), + (headers) -> prepareHeaders(headers) + .header("USER_ID", this.operatorId), + this.info); + } + } + + public class ArtifactDeleteAction extends ASDCArtifactAction<ArtifactDeleteAction> { + + private UUID artifactId; + + protected ArtifactDeleteAction(UUID theArtifactId) { + super(null); + this.artifactId = theArtifactId; + } + + protected ArtifactDeleteAction self() { + return this; + } + + public Future<JSONObject> execute() { + checkMandatory(); + return ASDC.this.delete(ref(this.artifactId), + (headers) -> prepareHeaders(headers) + .header("USER_ID", this.operatorId)); + } + } + + + + + public VFCMTCreateAction createVFCMT() { + return new VFCMTCreateAction(); + } + + protected static final String[] vfcmtMandatoryEntries = new String[] { "name", + "vendorName", + "vendorRelease", + "contactId" }; + + + public class VFCMTCreateAction extends ASDCAction<VFCMTCreateAction, JSONObject> { + + protected VFCMTCreateAction() { + + super(new JSONObject()); + this + .with("resourceType", "VFCMT") + .with("category", "Template") + .with("subcategory", "Monitoring Template") + .with("icon", "defaulticon"); + } + + protected VFCMTCreateAction self() { + return this; + } + + public VFCMTCreateAction withName(String theName) { + return with("name", theName); + } + + public VFCMTCreateAction withDescription(String theDescription) { + return with("description", theDescription); + } + + public VFCMTCreateAction withVendorName(String theVendorName) { + return with("vendorName", theVendorName); + } + + public VFCMTCreateAction withVendorRelease(String theVendorRelease) { + return with("vendorRelease", theVendorRelease); + } + + public VFCMTCreateAction withTags(String... theTags) { + for (String tag: theTags) + this.info.append("tags", tag); + return this; + } + + public VFCMTCreateAction withIcon(String theIcon) { + return with("icon", theIcon); + } + + protected String[] mandatoryInfoEntries() { + return ASDC.this.vfcmtMandatoryEntries; + } + + public VFCMTCreateAction withContact(String theContact) { + return with("contactId", theContact); + } + + public Future<JSONObject> execute() { + + this.info.putOnce("contactId", this.operatorId); + this.info.append("tags", info.optString("name")); + checkMandatory(); + return ASDC.this.post(refAssets(AssetType.resource), + (headers) -> prepareHeaders(headers) + .header("USER_ID", this.operatorId), + this.info); + } + + } + + public static JSONObject merge(JSONObject theOriginal, JSONObject thePatch) { + for (String key: (Set<String>)thePatch.keySet()) { + if (!theOriginal.has(key)) + theOriginal.put(key, thePatch.get(key)); + } + return theOriginal; + } + + protected URI refUri(String theRef) { + try { + return new URI(this.rootUri + theRef); + } + catch(URISyntaxException urisx) { + throw new UncheckedIOException(new IOException(urisx)); + } + } + + private HttpHeaders prepareHeaders() { + HttpHeaders headers = new HttpHeaders(); + headers.add(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((this.user + ":" + this.passwd).getBytes())); + headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE); + headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE); + headers.add("X-ECOMP-InstanceID", this.instanceId); + + return headers; + } + + private RequestEntity.HeadersBuilder prepareHeaders(RequestEntity.HeadersBuilder theBuilder) { + return theBuilder + .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((this.user + ":" + this.passwd).getBytes())) + .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) + .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header("X-ECOMP-InstanceID", this.instanceId); + } + + public <T> Future<T> fetch(String theRef, Class<T> theContentType) { + return exchange(theRef, HttpMethod.GET, new HttpEntity(prepareHeaders()), theContentType); + } + + public Future<JSONObject> post(String theRef, JSONObject thePost) { + return exchange(theRef, HttpMethod.POST, new HttpEntity<JSONObject>(thePost, prepareHeaders()), JSONObject.class); + } + + public Future<JSONObject> post(String theRef, UnaryOperator<RequestEntity.HeadersBuilder> theHeadersBuilder, JSONObject thePost) { + RequestEntity.BodyBuilder builder = RequestEntity.post(refUri(theRef)); + theHeadersBuilder.apply(builder); + + return exchange(theRef, HttpMethod.POST, builder.body(thePost), JSONObject.class); + } + + public Future<JSONObject> delete(String theRef, UnaryOperator<RequestEntity.HeadersBuilder> theHeadersBuilder) { + + RequestEntity.HeadersBuilder builder = RequestEntity.delete(refUri(theRef)); + theHeadersBuilder.apply(builder); + + return exchange(theRef, HttpMethod.DELETE, builder.build(), JSONObject.class); + } + + public <T> Future<T> exchange(String theRef, HttpMethod theMethod, HttpEntity theRequest, Class<T> theResponseType) { + + AsyncRestTemplate restTemplate = new AsyncRestTemplate(); + + List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters(); + converters.add(0, new JSONHttpMessageConverter()); + restTemplate.setMessageConverters(converters); + + restTemplate.setInterceptors(Collections.singletonList(new ContentMD5Interceptor())); + ASDCFuture<T> result = new ASDCFuture<T>(); + String uri = this.rootUri + theRef; + try { + restTemplate + .exchange(uri, theMethod, theRequest, theResponseType) + .addCallback(result.callback); + } + catch (RestClientException rcx) { + errLogger.log(LogLevel.WARN, this.getClass().getName(), "Failed to fetch {} {}", uri, rcx); + return Futures.failedFuture(rcx); + } + catch (Exception x) { + errLogger.log(LogLevel.WARN, this.getClass().getName(), "Failed to fetch {} {}", uri, x); + return Futures.failedFuture(x); + } + + return result; + } + + + + public class ASDCFuture<T> + extends Futures.BasicFuture<T> { + + private boolean http404toEmpty = false; + + ASDCFuture() { + } + + public ASDCFuture setHttp404ToEmpty(boolean doEmpty) { + this.http404toEmpty = doEmpty; + return this; + } + + ListenableFutureCallback<ResponseEntity<T>> callback = new ListenableFutureCallback<ResponseEntity<T>>() { + + public void onSuccess(ResponseEntity<T> theResult) { + ASDCFuture.this.result(theResult.getBody()); + } + + public void onFailure(Throwable theError) { + if (theError instanceof HttpClientErrorException) { + // if (theError.getRawStatusCode() == 404 && this.http404toEmpty) + // ASDCFuture.this.result(); //th eresult is of type T ... + // else + ASDCFuture.this.cause(new ASDCException((HttpClientErrorException)theError)); + } + else { + ASDCFuture.this.cause(theError); + } + } + }; + + } + + public class ContentMD5Interceptor implements AsyncClientHttpRequestInterceptor { + + @Override + public ListenableFuture<ClientHttpResponse> intercept( + HttpRequest theRequest, byte[] theBody, AsyncClientHttpRequestExecution theExecution) + throws IOException { + if (HttpMethod.POST == theRequest.getMethod()) { + HttpHeaders headers = theRequest.getHeaders(); + headers.add("Content-MD5", Base64Utils.encodeToString( + //DigestUtils.md5Digest(theBody))); + DigestUtils.md5Hex(theBody).getBytes())); + + } + return theExecution.executeAsync(theRequest, theBody); + } + } + + public static void main(String[] theArgs) throws Exception { + + CommandLineParser parser = new BasicParser(); + + String user_id = "jh0003"; + + Options options = new Options(); + options.addOption(OptionBuilder + .withArgName("target") + .withLongOpt("target") + .withDescription("target asdc system") + .hasArg() + .isRequired() + .create('t') ); + + options.addOption(OptionBuilder + .withArgName("action") + .withLongOpt("action") + .withDescription("one of: list, get, getartifact, checkin, checkout") + .hasArg() + .isRequired() + .create('a') ); + + options.addOption(OptionBuilder + .withArgName("assetType") + .withLongOpt("assetType") + .withDescription("one of resource, service, product") + .hasArg() + .isRequired() + .create('k') ); //k for 'kind' .. + + options.addOption(OptionBuilder + .withArgName("assetId") + .withLongOpt("assetId") + .withDescription("asset uuid") + .hasArg() + .create('u') ); //u for 'uuid' + + options.addOption(OptionBuilder + .withArgName("artifactId") + .withLongOpt("artifactId") + .withDescription("artifact uuid") + .hasArg() + .create('s') ); //s for 'stuff' + + options.addOption(OptionBuilder + .withArgName("listFilter") + .withLongOpt("listFilter") + .withDescription("filter for list operations") + .hasArg() + .create('f') ); //u for 'uuid' + + CommandLine line = null; + try { + line = parser.parse(options, theArgs); + } + catch(ParseException exp) { + errLogger.log(LogLevel.ERROR, ASDC.class.getName(), exp.getMessage()); + new HelpFormatter().printHelp("asdc", options); + return; + } + + ASDC asdc = new ASDC(); + asdc.setUri(new URI(line.getOptionValue("target"))); + + String action = line.getOptionValue("action"); + if (action.equals("list")) { + JSONObject filterInfo = new JSONObject( + line.hasOption("listFilter") ? + line.getOptionValue("listFilter") : "{}"); + JSONArray assets = + asdc.getAssets(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), JSONArray.class, + filterInfo.optString("category", null), filterInfo.optString("subCategory", null)) + .waitForResult(); + for (int i = 0; i < assets.length(); i++) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"> {}", assets.getJSONObject(i).toString(2)); + } + } + else if (action.equals("get")) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(), + asdc.getAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), + UUID.fromString(line.getOptionValue("assetId")), + JSONObject.class) + .waitForResult() + .toString(2) + ); + } + else if (action.equals("getartifact")) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(), + asdc.getAssetArtifact(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), + UUID.fromString(line.getOptionValue("assetId")), + UUID.fromString(line.getOptionValue("artifactId")), + String.class) + .waitForResult() + ); + } + else if (action.equals("checkin")) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(), + asdc.cycleAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), + UUID.fromString(line.getOptionValue("assetId")), + ASDC.LifecycleState.Checkin, + user_id, + "cli op") + .waitForResult() + .toString() + ); + } + else if (action.equals("checkout")) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(), + asdc.cycleAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), + UUID.fromString(line.getOptionValue("assetId")), + ASDC.LifecycleState.Checkout, + user_id, + "cli op") + .waitForResult() + .toString() + ); + } + else if (action.equals("cleanup")) { + JSONArray resources = asdc.getResources() + .waitForResult(); + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"Got {} resources", resources.length()); + + // vfcmt cleanup + for (int i = 0; i < resources.length(); i++) { + + JSONObject resource = resources.getJSONObject(i); + + if (resource.getString("resourceType").equals("VFCMT") && + resource.getString("name").contains("test")) { + + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"undocheckout for {}", resource.getString("uuid")); + + try { + asdc.cycleAsset(AssetType.resource, UUID.fromString(resource.getString("uuid")), LifecycleState.undocheckout, user_id, null) + .waitForResult(); + } + catch (Exception x) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"** {}", x); + } + } + } + + } + else { + try { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(), + asdc.createVFCMT() + .withName("Clonator") + .withDescription("Clone operation target 06192017") + .withVendorName("CloneInc") + .withVendorRelease("1.0") + .withTags("clone") + .withOperator(user_id) + .execute() + .waitForResult() + .toString() + ); + } + catch(Exception x) { + debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"Failed to create VFCMT: {}", x); + } + } + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCController.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCController.java new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCController.java diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCEngine.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCEngine.java new file mode 100644 index 0000000..73c7601 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCEngine.java @@ -0,0 +1,25 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import org.onap.sdc.dcae.composition.util.SystemProperties; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +@SpringBootApplication +public class ASDCEngine { + + /** + * Creates and returns a new instance of a {@link SystemProperties} class. + * + * @return New instance of {@link SystemProperties}. + */ + @Bean + public SystemProperties systemProperties() { + return new SystemProperties(); + } + + public static void main(String[] args) { + SpringApplication.run(ASDCEngine.class, args); + } + +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCException.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCException.java new file mode 100644 index 0000000..659653d --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCException.java @@ -0,0 +1,18 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import org.onap.sdc.dcae.errormng.BaseException; +import org.onap.sdc.dcae.errormng.RequestError; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +public class ASDCException extends BaseException { + + ASDCException(HttpClientErrorException error) { + super(error); + } + + public ASDCException(HttpStatus status, RequestError re){ + super(status, re); + } + +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCUtils.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCUtils.java new file mode 100644 index 0000000..1d70627 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCUtils.java @@ -0,0 +1,448 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONArray; +import org.json.JSONObject; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.catalog.commons.Actions; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.Futures; +import org.onap.sdc.dcae.catalog.commons.Recycler; +import org.onap.sdc.dcae.checker.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; + +import java.io.*; +import java.net.URI; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + + +@Component("asdcutils") +@Scope("singleton") +@ConfigurationProperties(prefix="asdcutils") +public class ASDCUtils { + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + @Autowired + private ASDC asdc; + + @Autowired + private Blueprinter blueprint; + + public ASDCUtils() { + // Making sonar happy + } + + public ASDCUtils(URI theASDCURI) { + this(theASDCURI, null); + } + + public ASDCUtils(URI theASDCURI, URI theBlueprinterURI) { + this.asdc = new ASDC(); + this.asdc.setUri(theASDCURI); + if (theBlueprinterURI != null) { + this.blueprint = new Blueprinter(); + this.blueprint.setUri(theBlueprinterURI); + } + } + + public ASDCUtils(ASDC theASDC) { + this(theASDC, null); + } + + public ASDCUtils(ASDC theASDC, Blueprinter theBlueprinter) { + this.asdc = theASDC; + this.blueprint = theBlueprinter; + } + + public CloneAssetArtifactsAction cloneAssetArtifacts(ASDC.AssetType theAssetType, UUID theSourceId, UUID theTargetId) { + return new CloneAssetArtifactsAction(this.asdc, theAssetType, theSourceId, theTargetId); + } + + public static class CloneAssetArtifactsAction extends ASDC.ASDCAction<CloneAssetArtifactsAction, List<JSONObject>> { + + private ASDC.AssetType assetType; + private UUID sourceId, targetId; + + protected CloneAssetArtifactsAction(ASDC theASDC, ASDC.AssetType theAssetType, UUID theSourceId, UUID theTargetId) { + theASDC.super(new JSONObject()); + this.assetType = theAssetType; + this.sourceId = theSourceId; + this.targetId = theTargetId; + } + + protected CloneAssetArtifactsAction self() { + return this; + } + + public CloneAssetArtifactsAction withLabel(String theLabel) { + return with("artifactLabel", theLabel); + } + + protected String[] mandatoryInfoEntries() { + return new String[] {}; + } + + public Future<List<JSONObject>> execute() { + checkMandatory(); + + final Actions.Sequence<JSONObject> sequencer = new Actions.Sequence<JSONObject>(); + + new Actions.Sequence().add(super.asdc().getAssetArchiveAction(this.assetType, this.sourceId)).add(super.asdc().getAssetAction(this.assetType, this.sourceId, JSONObject.class)).execute().setHandler(assetFuture -> { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "*** {}", assetFuture.result()); + processArtifacts((List) assetFuture.result(), (JSONObject theInfo, byte[] theData) -> { + theInfo.remove("artifactChecksum"); + theInfo.remove("artifactUUID"); + theInfo.remove("artifactVersion"); + theInfo.remove("artifactURL"); + theInfo.put("description", theInfo.remove("artifactDescription")); + theInfo.put("payloadData", Base64Utils.encodeToString(theData)); + return theInfo; + }, null).forEach(artifactInfo -> sequencer.add(super.asdc().createAssetArtifact(this.assetType, this.targetId).withInfo(ASDC.merge(artifactInfo, this.info)).withOperator(this.operatorId))); + sequencer.execute(); + }); + + return sequencer.future(); + } + } //the Action class + + /* */ + private static JSONObject lookupArtifactInfo(JSONArray theArtifacts, String theName) { + + for (int i = 0; theArtifacts != null && i < theArtifacts.length(); i++) { + JSONObject artifactInfo = theArtifacts.getJSONObject(i); + if (theName.equals(artifactInfo.getString("artifactName"))) { + debugLogger.log(LogLevel.DEBUG, ASDCUtils.class.getName(), "Found artifact info {}", artifactInfo); + return artifactInfo; + } + } + + return null; + } + + private static byte[] extractArtifactData(InputStream theEntryStream) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + byte[] buff = new byte[4096]; + int cnt = 0; + while ((cnt = theEntryStream.read(buff)) != -1) { + baos.write(buff, 0, cnt); + } + } finally { + baos.close(); + } + return baos.toByteArray(); + } + + /** + * Recycle a cdump, fetch all relevant ASDC artifacts, interact with Shu's toscalib service in order to generate + * a blueprint. No 'Action' object here as there is nothig to set up. + */ + public Future<Future<String>> buildBlueprint(Reader theCdump) { + + final Recycler recycler = new Recycler(); + Object template = null; + + try { + template = recycler.recycle(theCdump); + + } catch (Exception x) { + return Futures.failedFuture(x); + } + + JXPathContext jxroot = JXPathContext.newContext(template); + jxroot.setLenient(true); + + //based on the output of ASDCCatalog the node description will contain the UUID of the resource declaring it + List uuids = (List) StreamSupport.stream(Spliterators.spliteratorUnknownSize(jxroot.iterate("topology_template/node_templates/*/description"), 16), false).distinct().filter(desc -> desc != null) + //the desc contains the full URI and the resource uuid is the 5th path element + .map(desc -> desc.toString().split("/")[5]).collect(Collectors.toList()); + + //prepare fetching all archives/resource details + final Futures.Accumulator accumulator = new Futures.Accumulator(); + uuids.stream().forEach(uuid -> { + UUID rid = UUID.fromString((String) uuid); + accumulator.add(this.asdc.getAssetArchive(ASDC.AssetType.resource, rid)); + accumulator.add(this.asdc.getAsset(ASDC.AssetType.resource, rid, JSONObject.class)); + }); + + final byte[] templateData = recycler.toString(template).getBytes(/*"UTF-8"*/); + //retrieve all resource archive+details, prepare blueprint service request and send its request + return Futures.advance(accumulator.accumulate(), (List theArchives) -> { + Blueprinter.BlueprintAction action = blueprint.generateBlueprint(); + processArtifacts(theArchives, (JSONObject theInfo, byte[] theData) -> new JSONObject().put(theInfo.getString("artifactName").split("\\.")[0], Base64Utils.encodeToString(theData)), + (Stream<JSONObject> theAssetArtifacts) -> theAssetArtifacts.reduce(new JSONObject(), ASDC::merge)).forEach(artifactInfo -> action.withModelInfo(artifactInfo)); + + return action.withTemplateData(templateData).execute(); + }); + } + + public Future<Future<String>> buildBlueprintViaToscaLab(Reader theCdump) { + return processCdump(theCdump, (theTemplate, theArchives) -> { + Blueprinter.BlueprintAction action = blueprint.generateBlueprint(); + processArtifacts(theArchives, (JSONObject theInfo, byte[] theData) -> new JSONObject().put(theInfo.getString("artifactName").split("\\.")[0], Base64Utils.encodeToString(theData)), + (Stream<JSONObject> theAssetArtifacts) -> theAssetArtifacts.reduce(new JSONObject(), ASDC::merge)).forEach(artifactInfo -> action.withModelInfo(artifactInfo)); + + return action.withTemplateData(Recycler.toString(theTemplate).getBytes()).execute(); + + }); + } + + private static class Tracker implements TargetLocator { + + private static enum Position { + SCHEMA, TEMPLATE, TRANSLATE; + } + + private static final int Positions = Position.values().length; + + private List<Target> tgts = new ArrayList<Target>(3); + + public Tracker() { + clear(); + } + + public boolean addSearchPath(URI theURI) { + return false; + } + + public boolean addSearchPath(String thePath) { + return false; + } + + public Iterable<URI> searchPaths() { + return Collections.emptyList(); + } + + protected int position(String... theKeys) { + for (String key : theKeys) { + if ("schema".equals(key)) { + return Position.SCHEMA.ordinal(); + } + if ("template".equals(key)) { + return Position.TEMPLATE.ordinal(); + } + if ("translate".equals(key)) { + return Position.TRANSLATE.ordinal(); + } + } + return -1; + } + + public Target resolve(String theName) { + for (Target tgt : tgts) { + if (tgt != null && tgt.getName().equals(theName)) { + return tgt; + } + } + return null; + } + + public void track(JSONObject theInfo, final byte[] theData) { + String uri = theInfo.getString("artifactURL").split("/")[5]; + String name = theInfo.getString("artifactName"), desc = theInfo.getString("artifactDescription"), label = theInfo.getString("artifactLabel"); + int pos = position(desc, label); + + debugLogger.log(LogLevel.DEBUG, ASDCUtils.class.getName(), "Tracking {} at {}, {}", name, pos, theInfo.optString("artifactURL")); + + if (pos > -1) { + tgts.set(pos, new Target(name, URI.create("asdc:" + uri + "/" + name)) { + @Override + public Reader open(){ + return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(theData))); + } + }); + } + } + + public boolean hasSchema() { + return tgts.get(Position.SCHEMA.ordinal()) != null; + } + + public Target schema() { + return tgts.get(Position.SCHEMA.ordinal()); + } + + public boolean hasTemplate() { + return tgts.get(Position.TEMPLATE.ordinal()) != null; + } + + public Target template() { + return tgts.get(Position.TEMPLATE.ordinal()); + } + + public boolean hasTranslation() { + return tgts.get(Position.TRANSLATE.ordinal()) != null; + } + + public Target translation() { + return tgts.get(Position.TRANSLATE.ordinal()); + } + + public void clear() { + if (tgts.isEmpty()) { + for (int i = 0; i < Positions; i++) { + tgts.add(null); + } + } else { + Collections.fill(tgts, null); + } + } + } + + private Checker buildChecker() { + try { + return new Checker(); + } catch (CheckerException cx) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "CheckerException while creating Checker {}", cx); + return null; + } + } + + public Future<Catalog> buildCatalog(Reader theCdump) { + + // + //the purpose of the tracking is to be able to resolve import references within the 'space' of an + //asset's artifacts + //processing order is important too so we 'order the targets: schema, template, translation + // + final Tracker tracker = new Tracker(); + final Catalog catalog = Checker.buildCatalog(); + + return processCdump(theCdump, (theTemplate, theArchives) -> { + + final Checker checker = buildChecker(); + if (checker == null) { + return null; + } + checker.setTargetLocator(tracker); + + processArtifacts(theArchives, (JSONObject theInfo, byte[] theData) -> { + tracker.track(theInfo, theData); + return (Catalog) null; + }, + // aggregation: this is where the actual processing takes place now that + // we have all the targets + (Stream<Catalog> theAssetArtifacts) -> { + //the stream is full of nulls, ignore it, work with the tracker + + try { + if (tracker.hasSchema()) { + checker.check(tracker.schema(), catalog); + } + if (tracker.hasTemplate()) { + checker.check(tracker.template(), catalog); + } + if (tracker.hasTranslation()) { + checker.check(tracker.translation(), catalog); + } + } catch (CheckerException cx) { + //got to do better than this + errLogger.log(LogLevel.ERROR, ASDC.class.getName(),"CheckerException while checking catalog:{}", cx); + } finally { + tracker.clear(); + } + return checker.catalog(); + }); + + Target cdump = new Target("cdump", URI.create("asdc:cdump")); + cdump.setTarget(theTemplate); + + validateCatalog(catalog, checker, cdump); + + return catalog; + }); + } + + private void validateCatalog(Catalog catalog, Checker checker, Target cdump) { + try { + checker.validate(cdump, catalog); + } catch (CheckerException cx) { + errLogger.log(LogLevel.ERROR, ASDC.class.getName(),"CheckerException while building catalog:{}", cx); + } + } + + /* The common process of recycling, retrieving all related artifacts and then doing 'something' */ + private <T> Future<T> processCdump(Reader theCdump, BiFunction<Object, List, T> theProcessor) { + + final Recycler recycler = new Recycler(); + Object template = null; + try { + template = recycler.recycle(theCdump); + + } catch (Exception x) { + return Futures.failedFuture(x); + } + + JXPathContext jxroot = JXPathContext.newContext(template); + jxroot.setLenient(true); + + //based on the output of ASDCCatalog the node description will contain the UUID of the resource declaring it + //the desc contains the full URI and the resource uuid is the 5th path element + List uuids = (List) StreamSupport.stream(Spliterators.spliteratorUnknownSize(jxroot.iterate("topology_template/node_templates/*/description"), 16), false).distinct().filter(desc -> desc != null) + .map(desc -> desc.toString().split("/")[5]).collect(Collectors.toList()); + + //serialized fetch version + final Actions.Sequence sequencer = new Actions.Sequence(); + uuids.stream().forEach(uuid -> { + UUID rid = UUID.fromString((String) uuid); + sequencer.add(this.asdc.getAssetArchiveAction(ASDC.AssetType.resource, rid)); + sequencer.add(this.asdc.getAssetAction(ASDC.AssetType.resource, rid, JSONObject.class)); + }); + + final Object tmpl = template; + return Futures.advance(sequencer.execute(), (List theArchives) -> theProcessor.apply(tmpl, theArchives)); + } + + private static <T> Stream<T> processArtifacts(List theArtifactData, BiFunction<JSONObject, byte[], T> theProcessor, Function<Stream<T>, T> theAggregator) { + + Stream.Builder<T> assetBuilder = Stream.builder(); + + for (int i = 0; i < theArtifactData.size(); i = i + 2) { //cute old style loop + + JSONObject assetInfo = (JSONObject) theArtifactData.get(i + 1); + byte[] assetData = (byte[]) theArtifactData.get(i + 0); + + JSONArray artifacts = assetInfo.optJSONArray("artifacts"); + + Stream.Builder<T> artifactBuilder = Stream.builder(); + + try (ZipInputStream zipper = new ZipInputStream(new ByteArrayInputStream(assetData))){ + //we process the artifacts in the order they are stored in the archive .. fugly + for (ZipEntry zipped = zipper.getNextEntry(); zipped != null; zipped = zipper.getNextEntry()) { + JSONObject artifactInfo = lookupArtifactInfo(artifacts, StringUtils.substringAfterLast(zipped.getName(), "/")); + if (artifactInfo != null) { + artifactBuilder.add(theProcessor.apply(artifactInfo, extractArtifactData(zipper))); + } + zipper.closeEntry(); + } + } catch (IOException iox) { + errLogger.log(LogLevel.ERROR, ASDC.class.getName(), "IOException: {}", iox); + return null; + } + + if (theAggregator != null) { + assetBuilder.add(theAggregator.apply(artifactBuilder.build())); + } else { + artifactBuilder.build().forEach(entry -> assetBuilder.add(entry)); + } + } + + return assetBuilder.build(); + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCUtilsController.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCUtilsController.java new file mode 100644 index 0000000..4432712 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/ASDCUtilsController.java @@ -0,0 +1,76 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import java.io.StringReader; + +import java.util.UUID; +import java.util.Map; +import java.util.List; +import java.util.concurrent.Callable; + +import java.net.URI; +import java.net.URISyntaxException; + +import javax.servlet.http.HttpServletRequest; + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.springframework.beans.BeansException; + +import org.springframework.web.bind.annotation.RestController; + +import org.onap.sdc.dcae.catalog.asdc.ASDC; +import org.onap.sdc.dcae.catalog.asdc.ASDCUtils; +import org.onap.sdc.dcae.catalog.asdc.ASDCUtilsController; + +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.json.JSONObject; + + +@RestController +@ConfigurationProperties(prefix="asdcUtilsController") +public class ASDCUtilsController implements ApplicationContextAware { + + private ApplicationContext appCtx; + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + //Constants// + private static String NOT_CERTIFIED_CHECKOUT = "NOT_CERTIFIED_CHECKOUT"; + private static String NOT_CERTIFIED_CHECKIN = "NOT_CERTIFIED_CHECKIN"; + private static String CERTIFICATION_IN_PROGRESS = "CERTIFICATION_IN_PROGRESS"; + private static String CERTIFIED = "CERTIFIED"; + + + public void setApplicationContext(ApplicationContext theCtx) throws BeansException { + this.appCtx = theCtx; + } + + @PostConstruct + public void initController() { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"initASDCUtilsController"); + + //Done + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"ASDCUtilsController started"); + } + + @PreDestroy + public void cleanupController() { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(),"cleanupASDCUtilsController"); + } + +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/Blueprinter.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/Blueprinter.java new file mode 100644 index 0000000..3e78d38 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/Blueprinter.java @@ -0,0 +1,76 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import java.net.URI; + +import java.util.Collections; + +import org.json.JSONObject; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.catalog.commons.Action; +import org.onap.sdc.dcae.catalog.commons.Future; +import org.onap.sdc.dcae.catalog.commons.Http; +import org.json.JSONArray; + +import org.springframework.util.Base64Utils; + +import org.springframework.http.MediaType; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpEntity; +import org.springframework.stereotype.Component; +import org.springframework.context.annotation.Scope; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Component("blueprinter") +@Scope("singleton") +@ConfigurationProperties(prefix="blueprinter") +public class Blueprinter { + + + private URI serviceUri; + private OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + + public Blueprinter() { + } + + public void setUri(URI theUri) { + this.serviceUri = theUri; + } + + public BlueprintAction generateBlueprint() { + return new BlueprintAction(); + } + + public class BlueprintAction implements Action<String> { + + private JSONObject body = new JSONObject(); + + + protected BlueprintAction() { + } + + public BlueprintAction withModelData(byte[] theSchema, byte[] theTemplate, byte[] theTranslation) { + return this; + } + + public BlueprintAction withModelInfo(JSONObject theModelInfo) { + body.append("models", theModelInfo); + return this; + } + + public BlueprintAction withTemplateData(byte[] theData) { + body.put("template", Base64Utils.encodeToString(theData)); + return this; + } + + public Future<String> execute() { + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Blueprinter::execute() | PAYLOAD to TOSCA_LAB={}", body.toString()); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + return Http.exchange(serviceUri.toString(), HttpMethod.POST, new HttpEntity<String>(body.toString(), headers), String.class); + } + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/Cloudify.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/Cloudify.java new file mode 100644 index 0000000..3208bd2 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/catalog/asdc/Cloudify.java @@ -0,0 +1,249 @@ +package org.onap.sdc.dcae.catalog.asdc; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Stream; + +import org.apache.commons.jxpath.JXPathContext; +import org.apache.commons.jxpath.Pointer; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.onap.sdc.dcae.catalog.commons.ListBuilder; +import org.onap.sdc.dcae.catalog.commons.MapBuilder; +import org.onap.sdc.dcae.checker.Catalog; +import org.onap.sdc.dcae.checker.Construct; +import org.onap.sdc.dcae.checker.Target; + +import com.google.common.collect.Lists; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; + + +public class Cloudify { + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + Catalog catalog; + + public Cloudify(Catalog c) + { + catalog = c; + } + public class ModelTemplate { + public Map<String, Map> template; + public JXPathContext jx; + public String node; + public ModelTemplate(Map<String, Map> t, JXPathContext j, String node_name) + { + template = t; + jx = j; + node = node_name; + } + + public Object getPropValue(JXPathContext jx_src, String name) + { + try{ + Object ret = jx_src.getValue("properties/"+name+"/get_input"); + if (ret==null) + return jx_src.getValue("properties/"+name); + return getDefaultPropValue((String)ret); + } + catch (RuntimeException e) { + + } + try{ + return jx_src.getValue("properties/"+name+""); + } + catch (RuntimeException e) { + return null; + } + } + + public Object getDefaultPropValue(String name) { + try { + return jx.getValue("//"+name+"/default"); + } + catch (RuntimeException e) { + return null; + } + + } + } + + public class ModelTranslate { + public Map<String, Map> template; + public JXPathContext jx; + public String node; + + public ModelTranslate(Map<String, Map> t, JXPathContext j, String node_name) + { + template = t; + jx = j; + node = node_name; + } + + public String getTranslateName() + { + Map<String, Object> node_temp = (Map<String, Object>)jx.getValue("//node_templates"); + Iterator it = node_temp.keySet().iterator(); + if (it.hasNext()) + return node + "_"+ it.next(); + else + return null; + } + + public Map<String, Object> translate(JXPathContext jx_src, Map<String, Map> model_lib, String node_name) + { + for (Iterator prop_iter = jx.iteratePointers("//*[@get_input]"); prop_iter.hasNext();) { + + Pointer p = (Pointer)prop_iter.next(); + JXPathContext prop_path = jx.getRelativeContext(p); + + ModelTemplate src_model =(ModelTemplate) model_lib.get(node_name).get("model"); + + Object temp_o = src_model.getPropValue(jx_src, (String) prop_path.getValue("get_input")); + //prop_path.setValue(".", temp_o); + jx.setValue(p.asPath(), temp_o); + } + +// JXPathContext jx_src = JXPathContext.newContext(src); + for (Iterator req_iter = jx_src.iteratePointers("//*/node"); req_iter.hasNext();) { + Pointer p = (Pointer)req_iter.next(); + String req_node_name = (String)jx_src.getValue(p.asPath()); + + for (Iterator it = model_lib.keySet().iterator(); it.hasNext();) { + String key = (String) it.next(); + if (key.indexOf(req_node_name) <0 ) + continue; + ModelTranslate tt = (ModelTranslate) model_lib.get(key).get("translate"); + if (tt == null) + req_node_name = null; + else + { + req_node_name = tt.getTranslateName(); + } + break; + } + + } + + String tn_name = getTranslateName(); + + if (tn_name == null) + return (Map<String, Object>)jx.getValue("//node_templates"); + else + return (new MapBuilder<String, Object>().put(tn_name, jx.getValue("//node_templates/*")).build()); + } + + } + + public ModelTranslate findTranslateTemplate(String ty, String node) { + for (Target t: catalog.targets()) { + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "findTranslateTemplate: target {}", t.getName()); + if (t.getName().startsWith("translat") == false) { + continue; + } + + Map<String, Map>temp = (Map<String, Map>)t.getTarget(); + + JXPathContext jxroot = JXPathContext.newContext(temp); + try{ + String sub_type = (String)jxroot.getValue("topology_template/substitution_mappings/node_type"); + if (sub_type != null && sub_type.equals(ty)) { + return new ModelTranslate(temp, jxroot, node); + } + } + catch (RuntimeException e) { + errLogger.log(LogLevel.ERROR, this.getClass().getName(), "translate template {} does not have substitution mapping section", t.getName()); + } + } + return null; + } + + public ModelTemplate findModelTemplate(String ty, String node) { + for (Target t: catalog.targets()) { + + if (t.getName().startsWith("templat") == false) + continue; + Map<String, Map>temp = (Map<String, Map>)t.getTarget(); + + JXPathContext jxroot = JXPathContext.newContext(temp); + for (Iterator it = jxroot.iterate("topology_template/node_templates/*/type"); it.hasNext();) { + String node_type = (String)it.next(); + if (node_type != null && node_type.equals(ty)) { + return new ModelTemplate(temp, jxroot, node); + } + } + } + return null; + } + + public Map<String, Object> createBlueprint() { + + Map<String, Map> target_temp = null; + for (Target t: catalog.targets()) { + + if (t.getName().equals("cdump")) { + target_temp = catalog.getTargetTemplates(t, Construct.Node); + } + } + + JXPathContext jxroot = JXPathContext.newContext(target_temp); + + Map<String, Object> output_temp = new HashMap<String, Object>(); + Map<String, Map> model_lib = new HashMap<String, Map>(); + + for (Iterator iter = target_temp.keySet().iterator(); iter.hasNext();) + { + String node_key = (String)iter.next(); + //jxroot.getVariables().declareVariable("name", target_temp.get(node_key)); + //String node_type = (String)jxroot.getValue("$name/type"); + String node_type = (String)jxroot.getValue(node_key+"/type"); + + ModelTranslate t_temp = findTranslateTemplate(node_type, node_key); + ModelTemplate t_model = findModelTemplate(node_type, node_key); + + model_lib.put(node_key, new MapBuilder() + .put("model", t_model) + .put("translate", t_temp) + .build()); + } + + for (Iterator iter = model_lib.keySet().iterator(); iter.hasNext();) { + String node_key = (String) iter.next(); + ModelTranslate t = (ModelTranslate) model_lib.get(node_key).get("translate"); + JXPathContext jxnode = jxroot.getRelativeContext(jxroot.getPointer(node_key)); + if (t != null) { + Map<String, Object> t_output =t.translate(jxnode, model_lib, node_key); + if (t_output != null) + output_temp.putAll(t_output); + } + + } + + return new MapBuilder<String, Object>() + .put("tosca_definitions_version", new String("cloudify_dsl_1_3")) + .put("imports", new ListBuilder() + .add(new MapBuilder() + .put("cloudify", + "http://www.getcloudify.org/spec/cloudify/3.4/types.yaml") + .build()) + .build()) + .put("node_templates", output_temp) + .build(); + + } + + public String createBlueprintDocument() { + DumperOptions options = new DumperOptions(); + options.setWidth(1000000); + Yaml yaml = new Yaml(options); + return yaml.dump(createBlueprint()); + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/client/ISdcClient.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/client/ISdcClient.java new file mode 100644 index 0000000..554991a --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/client/ISdcClient.java @@ -0,0 +1,47 @@ +package org.onap.sdc.dcae.client; + +import org.onap.sdc.dcae.composition.restmodels.CreateVFCMTRequest; +import org.onap.sdc.dcae.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; +import org.onap.sdc.dcae.enums.AssetType; + +import java.util.List; + +public interface ISdcClient { + + ResourceDetailed getResource(String uuid, String requestId) throws Exception; + + ServiceDetailed getService(String uuid, String requestId) throws Exception; + + List<Resource> getResources(String resourceType, String category, String subcategory, String requestId) throws Exception; + + List<Service> getServices(String requestId) throws Exception; + + String addExternalMonitoringReference(String userId, CreateVFCMTRequest resource, ReferenceUUID vfiUuid, String requestId); + + void deleteExternalMonitoringReference(String userId, String context, String uuid, String vfiName, String vfcmtUuid, String requestId); + + ResourceDetailed createResource(String userId, CreateVFCMTRequest resource, String requestId) throws Exception; + + ResourceDetailed changeResourceLifecycleState(String userId, String uuid, String lifecycleOperation, String userRemarks, String requestId) throws Exception; + + ServiceDetailed changeServiceLifecycleState(String userId, String uuid, String lifecycleOperation, String userRemarks, String requestId) throws Exception; + + Asset changeAssetLifecycleState(String userId, String uuid, String lifecycleOperation, String userRemarks, AssetType assetType, String requestId) throws Exception; + + String getResourceArtifact(String resourceUuid, String artifactUuid, String requestId) throws Exception; + + Artifact createResourceArtifact(String userId, String resourceUuid, Artifact artifact, String requestId) throws Exception; + + Artifact updateResourceArtifact(String userId, String resourceUuid, Artifact artifact, String requestId) throws Exception; + + void deleteResourceArtifact(String userId, String resourceUuid, String artifactId, String requestId) throws Exception; + + Artifact createVfInstanceArtifact(String userId, String serviceUuid, String normalizedInstanceName, Artifact artifact, String requestId) throws Exception; + + Artifact updateVfInstanceArtifact(String userId, String serviceUuid, String normalizedInstanceName, Artifact artifact, String requestId) throws Exception; + + ExternalReferencesMap getMonitoringReferences(String context, String uuid, String version, String requestId); + + void deleteInstanceResourceArtifact(String userId, String context, String serviceUuid, String normalizedVfiName, String artifactUuid, String requestId); +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/client/SdcRestClient.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/client/SdcRestClient.java new file mode 100644 index 0000000..058d9c7 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/client/SdcRestClient.java @@ -0,0 +1,221 @@ +package org.onap.sdc.dcae.client; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicHeader; +import org.onap.sdc.dcae.composition.restmodels.CreateVFCMTRequest; +import org.onap.sdc.dcae.composition.restmodels.ReferenceUUID; +import org.onap.sdc.dcae.composition.restmodels.sdc.*; +import org.onap.sdc.dcae.composition.util.DcaeBeConstants; +import org.onap.sdc.dcae.composition.util.SystemProperties; +import org.onap.sdc.dcae.enums.AssetType; +import org.onap.sdc.dcae.enums.SdcConsumerInfo; +import org.onap.sdc.dcae.utils.Normalizers; +import org.onap.sdc.dcae.utils.SDCResponseErrorHandler; +import org.onap.sdc.dcae.utils.SdcRestClientUtils; +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.Enums.LogLevel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.stereotype.Component; +import org.springframework.util.Base64Utils; +import org.springframework.web.client.*; + +import javax.annotation.PostConstruct; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Component("sdcrestclient") +public class SdcRestClient implements ISdcClient { + + @Autowired + private SystemProperties systemProperties; + + private static final String SLASH = "/"; + private static final String ECOMP_INSTANCE_ID_HEADER = "X-ECOMP-InstanceID"; + private static final String ECOMP_REQUEST_ID_HEADER = "X-ECOMP-RequestID"; + private static final String USER_ID_HEADER = "USER_ID"; + private static final String RESOURCES_PATH = "resources"; + private static final String SERVICES_PATH = "services"; + private static final String ARTIFACTS_PATH = "artifacts"; + private static final String CONTENT_MD5_HEADER = "Content-MD5"; + private static final String RESOURCE_INSTANCES_PATH = "resourceInstances"; + private static final String LIFECYCLE_STATE_PATH = "lifecycleState/{lifecycleOperation}"; + private static final String METADATA_PATH = "metadata"; + private static final String VERSION_PATH = "version"; + private static final String MONITORING_REFERENCES_PATH = "externalReferences/monitoring"; + + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + private String uri; + + private RestTemplate client; + + @PostConstruct + private void init() { + URI configUri = URI.create(systemProperties.getProperties().getProperty(DcaeBeConstants.Config.URI)); + EnumMap<SdcConsumerInfo, String> userInfo = SdcRestClientUtils.extractConsumerInfoFromUri(configUri); + CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultHeaders(defaultHeaders(userInfo)).build(); + HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); + requestFactory.setHttpClient(httpClient); + client = new RestTemplate(requestFactory); + client.setErrorHandler(new SDCResponseErrorHandler()); + uri = userInfo.get(SdcConsumerInfo.CATALOG_URL); + } + + private List<BasicHeader> defaultHeaders(EnumMap<SdcConsumerInfo, String> userInfo) { + List<BasicHeader> headers = new ArrayList<>(); + headers.add(new BasicHeader(HttpHeaders.AUTHORIZATION, userInfo.get(SdcConsumerInfo.AUTH))); + headers.add(new BasicHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)); + headers.add(new BasicHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE)); + headers.add(new BasicHeader(ECOMP_INSTANCE_ID_HEADER, userInfo.get(SdcConsumerInfo.INSTANCE_ID))); + return headers; + } + + public ResourceDetailed getResource(String uuid, String requestId) { + String url = buildRequestPath(RESOURCES_PATH, uuid, METADATA_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Get resource from SDC. URL={}", url); + return getObject(url, requestId, ResourceDetailed.class); + } + + public ServiceDetailed getService(String uuid, String requestId) { + String url = buildRequestPath(SERVICES_PATH, uuid, METADATA_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Get service from SDC. URL={}", url); + return getObject(url, requestId, ServiceDetailed.class); + } + + public List<Resource> getResources(String resourceType, String category, String subcategory, String requestId) { + String url = buildRequestPath(RESOURCES_PATH, SdcRestClientUtils.buildResourceFilterQuery(resourceType, category, subcategory)); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Get resources from SDC. URL={}", url); + return Arrays.asList(getObject(url, requestId, Resource[].class)); + } + + public List<Service> getServices(String requestId) { + String url = buildRequestPath(SERVICES_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Get services from SDC. URL={}", url); + return Arrays.asList(getObject(url, requestId, Service[].class)); + } + + public String addExternalMonitoringReference(String userId, CreateVFCMTRequest resource, ReferenceUUID vfcmtUuid, String requestId) { + String url = buildRequestPath(resource.getContextType(), resource.getServiceUuid(), RESOURCE_INSTANCES_PATH, + Normalizers.normalizeComponentInstanceName(resource.getVfiName()), MONITORING_REFERENCES_PATH); + + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Connecting service id {} name {} to vfcmt {} URL={}", + resource.getServiceUuid(), resource.getVfiName(), vfcmtUuid.getReferenceUUID(), url); + + return client.postForObject(url, new HttpEntity<>(vfcmtUuid, postResourceHeaders(userId, requestId)), + String.class); + } + + public void deleteExternalMonitoringReference(String userId, String context, String uuid, String normalizeVfiName, String vfcmtUuid, String requestId) { + String url = buildRequestPath(context, uuid, RESOURCE_INSTANCES_PATH, + normalizeVfiName, MONITORING_REFERENCES_PATH, vfcmtUuid); + client.exchange(url, HttpMethod.DELETE, new HttpEntity(postResourceHeaders(userId, requestId)), String.class); + } + + public ResourceDetailed createResource(String userId, CreateVFCMTRequest resource, String requestId) { + String url = buildRequestPath(RESOURCES_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Create SDC resource with name {} URL={}", resource.getName(), url); + return client.postForObject(url, new HttpEntity<>(resource, postResourceHeaders(userId, requestId)), ResourceDetailed.class); + } + + public ResourceDetailed changeResourceLifecycleState(String userId, String uuid, String lifecycleOperation, String userRemarks, String requestId) { + String url = buildRequestPath(RESOURCES_PATH, uuid, LIFECYCLE_STATE_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Change SDC resource lifecycle state ({}). URL={}", lifecycleOperation, url); + return client.postForObject(url, new HttpEntity<>(SdcRestClientUtils.buildUserRemarksObject(userRemarks), postResourceHeaders(userId, requestId)), ResourceDetailed.class, lifecycleOperation); + } + + public ServiceDetailed changeServiceLifecycleState(String userId, String uuid, String lifecycleOperation, String userRemarks, String requestId) { + String url = buildRequestPath(SERVICES_PATH, uuid, LIFECYCLE_STATE_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Change SDC service lifecycle state ({}). URL={}", lifecycleOperation, url); + return client.postForObject(url, new HttpEntity<>(SdcRestClientUtils.buildUserRemarksObject(userRemarks), postResourceHeaders(userId, requestId)), ServiceDetailed.class, lifecycleOperation); + } + + public Asset changeAssetLifecycleState(String userId, String uuid, String lifecycleOperation, String userRemarks, AssetType assetType, String requestId) { + return AssetType.RESOURCE == assetType ? changeResourceLifecycleState(userId, uuid, lifecycleOperation, userRemarks, requestId) : changeServiceLifecycleState(userId, uuid, lifecycleOperation, userRemarks, requestId); + } + + public String getResourceArtifact(String resourceUuid, String artifactUuid, String requestId) { + String url = buildRequestPath(RESOURCES_PATH, resourceUuid, ARTIFACTS_PATH, artifactUuid); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Get resource artifact from SDC. URL={}", url); + return getObject(url, requestId, String.class); + } + + public Artifact createResourceArtifact(String userId, String resourceUuid, Artifact artifact, String requestId) throws Exception { + String url = buildRequestPath(RESOURCES_PATH, resourceUuid, ARTIFACTS_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Create SDC resource artifact. URL={}", url); + String artifactData = SdcRestClientUtils.artifactToString(artifact); + return client.postForObject(url, new HttpEntity<>(artifactData, postArtifactHeaders(userId, artifactData, requestId)), Artifact.class); + } + + public Artifact updateResourceArtifact(String userId, String resourceUuid, Artifact artifact, String requestId) throws Exception { + String url = buildRequestPath(RESOURCES_PATH, resourceUuid, ARTIFACTS_PATH, artifact.getArtifactUUID()); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Update SDC resource artifact. URL={}", url); + String artifactData = SdcRestClientUtils.artifactToString(artifact); + return client.postForObject(url, new HttpEntity<>(artifactData, postArtifactHeaders(userId, artifactData, requestId)), Artifact.class); + } + + public void deleteResourceArtifact(String userId, String resourceUuid, String artifactId, String requestId) { + String url = buildRequestPath(RESOURCES_PATH, resourceUuid, ARTIFACTS_PATH, artifactId); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Delete SDC resource artifact. URL={}", url); + client.exchange(url, HttpMethod.DELETE, new HttpEntity(postResourceHeaders(userId, requestId)), Artifact.class); + } + + public Artifact createVfInstanceArtifact(String userId, String serviceUuid, String normalizedInstanceName, Artifact artifact, String requestId) throws Exception { + String url = buildRequestPath(SERVICES_PATH, serviceUuid, RESOURCE_INSTANCES_PATH, normalizedInstanceName, ARTIFACTS_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Create SDC resource instance artifact. URL={}", url); + String artifactData = SdcRestClientUtils.artifactToString(artifact); + return client.postForObject(url, new HttpEntity<>(artifactData, postArtifactHeaders(userId, artifactData, requestId)), Artifact.class); + } + + public Artifact updateVfInstanceArtifact(String userId, String serviceUuid, String normalizedInstanceName, Artifact artifact, String requestId) throws Exception { + String url = buildRequestPath(SERVICES_PATH, serviceUuid, RESOURCE_INSTANCES_PATH, normalizedInstanceName, ARTIFACTS_PATH, artifact.getArtifactUUID()); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Update SDC resource instance artifact. URL={}", url); + String artifactData = SdcRestClientUtils.artifactToString(artifact); + return client.postForObject(url, new HttpEntity<>(artifactData, postArtifactHeaders(userId, artifactData, requestId)), Artifact.class); + } + + public ExternalReferencesMap getMonitoringReferences(String context, String uuid, String version, String requestId) { + String url = buildRequestPath(context, uuid, VERSION_PATH, version, MONITORING_REFERENCES_PATH); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Get SDC service monitoring references. URL={}", url); + return getObject(url, requestId, ExternalReferencesMap.class); + } + + public void deleteInstanceResourceArtifact(String userId, String context, String serviceUuid, String normalizedVfiName, String artifactUuid, String requestId) { + String url = buildRequestPath(context, serviceUuid, RESOURCE_INSTANCES_PATH, normalizedVfiName, ARTIFACTS_PATH, artifactUuid); + debugLogger.log(LogLevel.DEBUG, this.getClass().getName(), "Delete SDC instance resource artifact. URL={}", url); + client.exchange(url, HttpMethod.DELETE, new HttpEntity(postResourceHeaders(userId, requestId)), Artifact.class); + } + + private HttpHeaders postResourceHeaders(String userId, String requestId) { + HttpHeaders headers = requestHeader(requestId); + headers.setContentType(MediaType.APPLICATION_JSON_UTF8); + headers.add(USER_ID_HEADER, userId); + return headers; + } + + private HttpHeaders postArtifactHeaders(String userId, String artifact, String requestId) { + HttpHeaders headers = postResourceHeaders(userId, requestId); + String md5 = Base64Utils.encodeToString(DigestUtils.md5Hex(artifact).getBytes()); + headers.add(CONTENT_MD5_HEADER, md5); + return headers; + } + + private HttpHeaders requestHeader(String requestId){ + HttpHeaders headers = new HttpHeaders(); + headers.add(ECOMP_REQUEST_ID_HEADER, requestId); + return headers; + } + + private <T> T getObject(String url, String requestId, Class<T> clazz) { + return client.exchange(url, HttpMethod.GET, new HttpEntity<>(requestHeader(requestId)), clazz).getBody(); + } + + private String buildRequestPath(String... args){ + return uri + Stream.of(args).collect(Collectors.joining(SLASH)); + } +}
\ No newline at end of file diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/ArtifactGroupType.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/ArtifactGroupType.java new file mode 100644 index 0000000..98e78c6 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/ArtifactGroupType.java @@ -0,0 +1,5 @@ +package org.onap.sdc.dcae.enums; + +public enum ArtifactGroupType { + DEPLOYMENT +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/ArtifactType.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/ArtifactType.java new file mode 100644 index 0000000..2da4cc7 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/ArtifactType.java @@ -0,0 +1,16 @@ +package org.onap.sdc.dcae.enums; + +public enum ArtifactType { + DCAE_TOSCA, + DCAE_JSON, + DCAE_POLICY, + DCAE_DOC, + DCAE_EVENT, + DCAE_INVENTORY_TOSCA, + DCAE_INVENTORY_JSON, + DCAE_INVENTORY_POLICY, + DCAE_INVENTORY_DOC, + DCAE_INVENTORY_BLUEPRINT, + DCAE_INVENTORY_EVENT, + OTHER +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/AssetType.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/AssetType.java new file mode 100644 index 0000000..576643f --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/AssetType.java @@ -0,0 +1,5 @@ +package org.onap.sdc.dcae.enums; + +public enum AssetType { + RESOURCE, SERVICE +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/LifecycleOperationType.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/LifecycleOperationType.java new file mode 100644 index 0000000..80e01df --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/LifecycleOperationType.java @@ -0,0 +1,16 @@ +package org.onap.sdc.dcae.enums; + + +public enum LifecycleOperationType { + CHECKIN("checkin"), CHECKOUT("checkout"), CERTIFY("certify"), UNDO_CHECKOUT("undoCheckout"); + + private String value; + + LifecycleOperationType(String value){ + this.value = value; + } + + public String getValue(){ + return value; + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/SdcConsumerInfo.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/SdcConsumerInfo.java new file mode 100644 index 0000000..aecb61d --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/enums/SdcConsumerInfo.java @@ -0,0 +1,5 @@ +package org.onap.sdc.dcae.enums; + +public enum SdcConsumerInfo { + AUTH, INSTANCE_ID, CATALOG_URL +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/AbstractSdncException.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/AbstractSdncException.java new file mode 100644 index 0000000..360e28b --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/AbstractSdncException.java @@ -0,0 +1,97 @@ +package org.onap.sdc.dcae.errormng; + + +import org.onap.sdc.common.onaplog.OnapLoggerDebug; +import org.onap.sdc.common.onaplog.OnapLoggerError; +import org.onap.sdc.common.onaplog.Enums.LogLevel; + +import java.util.Arrays; +import java.util.Formatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AbstractSdncException { + private String messageId; + + private String text; + + private String[] variables; + + private static OnapLoggerError errLogger = OnapLoggerError.getInstance(); + private static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance(); + + private final static Pattern ERROR_PARAM_PATTERN = Pattern.compile("%\\d"); + + public AbstractSdncException() { + } + + public AbstractSdncException(String messageId, String text, String[] variables) { + super(); + this.messageId = messageId; + this.text = text; + this.variables = validateParameters(messageId, text, variables); + } + + private String[] validateParameters(String messageId, String text, String[] variables) { + String[] res = null; + Matcher m = ERROR_PARAM_PATTERN.matcher(text); + int expectedParamsNum = 0; + while (m.find()) { + expectedParamsNum += 1; + } + int actualParamsNum = (variables != null) ? variables.length : 0; + if (actualParamsNum < expectedParamsNum) { + errLogger.log(LogLevel.WARN, this.getClass().getName(), + "Received less parameters than expected for error with messageId {}, expected: {}, actual: {}. Missing parameters are padded with null values.", + messageId, expectedParamsNum, actualParamsNum); + } else if (actualParamsNum > expectedParamsNum) { + errLogger.log(LogLevel.WARN, this.getClass().getName(), + "Received more parameters than expected for error with messageId {}, expected: {}, actual: {}. Extra parameters are ignored.", + messageId, expectedParamsNum, actualParamsNum); + } + if (variables != null) { + res = Arrays.copyOf(variables, expectedParamsNum); + } + + return res; + } + + public String getMessageId() { + return this.messageId; + } + + public String getText() { + return text; + } + + public String[] getVariables() { + return variables; + } + + public void setMessageId(String messageId) { + this.messageId = messageId; + } + + public void setText(String text) { + this.text = text; + } + + public void setVariables(String[] variables) { + this.variables = variables; + } + + public String getFormattedErrorMessage() { + String res; + if (variables != null && variables.length > 0) { + Formatter formatter = new Formatter(); + try { + res = formatter.format(this.text.replaceAll("%\\d", "%s"), (Object[]) this.variables).toString(); + } finally { + formatter.close(); + } + } else { + res = this.text; + } + return res; + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/BaseException.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/BaseException.java new file mode 100644 index 0000000..b559634 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/BaseException.java @@ -0,0 +1,61 @@ +package org.onap.sdc.dcae.errormng; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.google.gson.Gson; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +public class BaseException extends HttpClientErrorException { + + private static Gson gson = new Gson(); + + protected RequestError requestError; + + public RequestError getRequestError() { + return requestError; + } + + public void setRequestError(RequestError requestError) { + this.requestError = requestError; + } + + public BaseException(HttpClientErrorException theError) { + super(theError.getStatusCode()); + String body = theError.getResponseBodyAsString(); + if (body != null) { + requestError = extractRequestError(body); + } + } + + public BaseException(HttpStatus status, RequestError re){ + super(status); + requestError = re; + } + + private RequestError extractRequestError(String error) { + ResponseFormat responseFormat = gson.fromJson(error, ResponseFormat.class); + return responseFormat.getRequestError(); + } + + @JsonIgnore + public String getMessageId() { + return requestError.getMessageId(); + } + + @JsonIgnore + public String[] getVariables() { + return requestError.getVariables(); + } + + @JsonIgnore + public String getText(){ + return requestError.getText(); + } + + @Override + @JsonIgnore + public String getMessage() { + return requestError.getFormattedMessage(); + } + +}
\ No newline at end of file diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/OkResponseInfo.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/OkResponseInfo.java new file mode 100644 index 0000000..53bdf3e --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/OkResponseInfo.java @@ -0,0 +1,8 @@ +package org.onap.sdc.dcae.errormng; + +public class OkResponseInfo extends AbstractSdncException { + + public OkResponseInfo(String messageId, String text, String[] variables) { + super(messageId, text, variables); + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/PolicyException.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/PolicyException.java new file mode 100644 index 0000000..3fc2d71 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/PolicyException.java @@ -0,0 +1,11 @@ +package org.onap.sdc.dcae.errormng; + +public class PolicyException extends AbstractSdncException { + + public PolicyException(String messageId, String text, String[] variables) { + super(messageId, text, variables); + } + + public PolicyException() { + } +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/RequestError.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/RequestError.java new file mode 100644 index 0000000..00fe3f2 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/RequestError.java @@ -0,0 +1,65 @@ +package org.onap.sdc.dcae.errormng; + +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class RequestError { + private PolicyException policyException; + private ServiceException serviceException; + private OkResponseInfo okResponseInfo; + private List<ServiceException> serviceExceptions; + + public PolicyException getPolicyException() { + return policyException; + } + + public ServiceException getServiceException() { + return serviceException; + } + + public OkResponseInfo getOkResponseInfo() { + return okResponseInfo; + } + + public void setPolicyException(PolicyException policyException) { + this.policyException = policyException; + } + + void setServiceException(ServiceException serviceException) { + this.serviceException = serviceException; + } + + void setOkResponseInfo(OkResponseInfo okResponseInfo) { + this.okResponseInfo = okResponseInfo; + } + + public List<ServiceException> getServiceExceptions() { + return serviceExceptions; + } + + void setServiceExceptions(List<ServiceException> serviceExceptions) { + this.serviceExceptions = serviceExceptions; + } + + String getFormattedMessage() { + return getError().getFormattedErrorMessage(); + } + + String getMessageId() { + return getError().getMessageId(); + } + + String[] getVariables() { + return getError().getVariables(); + } + + String getText() { + return getError().getText(); + } + + AbstractSdncException getError() { + return null != serviceException ? serviceException : null != policyException ? policyException : okResponseInfo; + } +}
\ No newline at end of file diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormat.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormat.java new file mode 100644 index 0000000..ffdce70 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/ResponseFormat.java @@ -0,0 +1,75 @@ +package org.onap.sdc.dcae.errormng; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; + +import java.util.List; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ResponseFormat { + + @JsonIgnore + private int status; + private RequestError requestError; + private String notes = ""; + + public String getNotes() { + return notes; + } + + void setNotes(String notes) { + this.notes = notes; + } + + public ResponseFormat() { + super(); + } + + public ResponseFormat(int status) { + super(); + this.status = status; + } + + + public void setStatus(int status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + public RequestError getRequestError() { + return requestError; + } + + public void setRequestError(RequestError requestError) { + this.requestError = requestError; + } + + void setPolicyException(PolicyException policyException) { + this.requestError = new RequestError(); + requestError.setPolicyException(policyException); + } + + void setServiceException(ServiceException serviceException) { + this.requestError = new RequestError(); + requestError.setServiceException(serviceException); + } + + void setOkResponseInfo(OkResponseInfo okResponseInfo) { + this.requestError = new RequestError(); + requestError.setOkResponseInfo(okResponseInfo); + } + + void setServiceExceptions(List<ServiceException> serviceExceptions) { + this.requestError = new RequestError(); + requestError.setServiceExceptions(serviceExceptions); + } + + @Override + public String toString() { + return "ResponseFormat[" + "status=" + status + ", requestError=" + requestError + ']'; + } + +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/ServiceException.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/ServiceException.java new file mode 100644 index 0000000..163a07f --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/errormng/ServiceException.java @@ -0,0 +1,12 @@ +package org.onap.sdc.dcae.errormng; + +public class ServiceException extends AbstractSdncException { + + public ServiceException(String messageId, String text, String[] variables) { + super(messageId, text, variables); + } + + public ServiceException() { + } + +}
\ No newline at end of file diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/Normalizers.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/Normalizers.java new file mode 100644 index 0000000..4719607 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/Normalizers.java @@ -0,0 +1,34 @@ +package org.onap.sdc.dcae.utils; + +import org.apache.commons.lang3.text.WordUtils; + +import java.util.regex.Pattern; + +public final class Normalizers { + + private static final Pattern COMPONENT_NAME_DELIMITER_PATTERN = Pattern.compile("[.\\-_]+"); + private static final Pattern ARTIFACT_LABEL_DELIMITER_PATTERN = Pattern.compile("[ \\-+._]+"); + private static final Pattern COMPONENT_INSTANCE_NAME_DELIMITER_PATTERN = Pattern.compile("[ \\-.]+"); + + + public static String normalizeComponentName(String name) { + String normalizedName = name.toLowerCase(); + normalizedName = COMPONENT_NAME_DELIMITER_PATTERN.matcher(normalizedName).replaceAll(" "); + String[] split = normalizedName.split(" "); + StringBuffer sb = new StringBuffer(); + for (String splitElement : split) { + String capitalize = WordUtils.capitalize(splitElement); + sb.append(capitalize); + } + return sb.toString(); + } + + public static String normalizeArtifactLabel(String label) { + return ARTIFACT_LABEL_DELIMITER_PATTERN.matcher(label).replaceAll("").toLowerCase(); + } + + public static String normalizeComponentInstanceName(String name) { + return COMPONENT_INSTANCE_NAME_DELIMITER_PATTERN.matcher(name).replaceAll("").toLowerCase(); + } + +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/SDCResponseErrorHandler.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/SDCResponseErrorHandler.java new file mode 100644 index 0000000..64da66a --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/SDCResponseErrorHandler.java @@ -0,0 +1,43 @@ +package org.onap.sdc.dcae.utils; + +import com.google.gson.Gson; +import org.onap.sdc.dcae.catalog.asdc.ASDCException; +import org.onap.sdc.dcae.errormng.RequestError; +import org.onap.sdc.dcae.errormng.ResponseFormat; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.ResponseErrorHandler; + +import java.io.IOException; + +public class SDCResponseErrorHandler implements ResponseErrorHandler { + + private ResponseErrorHandler errorHandler = new DefaultResponseErrorHandler(); + + private static Gson gson = new Gson(); + + public void handleError(ClientHttpResponse response) throws IOException { + try{ + errorHandler.handleError(response); + } catch (HttpClientErrorException e) { + RequestError re = extractRequestError(e); + throw null == re ? e : new ASDCException(e.getStatusCode(), re); + } + } + + public boolean hasError(ClientHttpResponse response) throws IOException{ + return errorHandler.hasError(response); + } + + private RequestError extractRequestError(HttpClientErrorException error) { + try { + String body = error.getResponseBodyAsString(); + ResponseFormat responseFormat = gson.fromJson(body, ResponseFormat.class); + return responseFormat.getRequestError(); + } catch (Exception e) { + return null; + } + } + +} diff --git a/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/SdcRestClientUtils.java b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/SdcRestClientUtils.java new file mode 100644 index 0000000..33c2f49 --- /dev/null +++ b/dcaedt_catalog/asdc/src/main/java/org/onap/sdc/dcae/utils/SdcRestClientUtils.java @@ -0,0 +1,85 @@ +package org.onap.sdc.dcae.utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.onap.sdc.dcae.composition.restmodels.sdc.Artifact; +import org.onap.sdc.dcae.enums.ArtifactGroupType; +import org.onap.sdc.dcae.enums.SdcConsumerInfo; +import org.springframework.util.Base64Utils; +import org.springframework.util.StringUtils; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.stream.Collectors; + +public class SdcRestClientUtils { + + private static final String SDC_CATALOG_PATH = "/sdc/v1/catalog/"; + + // TODO consider moving params elsewhere (user/password/instanceId can be constant) + public static EnumMap<SdcConsumerInfo, String> extractConsumerInfoFromUri(URI configUri) { + EnumMap<SdcConsumerInfo, String> userInfoMap = new EnumMap<>(SdcConsumerInfo.class); + String userInfo = configUri.getUserInfo(); + if (userInfo != null) { + userInfoMap.put(SdcConsumerInfo.AUTH, "Basic "+ Base64Utils.encodeToString(userInfo.getBytes())); + } + String fragment = configUri.getFragment(); + if (fragment == null) + throw new IllegalArgumentException("The URI must contain a fragment specification, to be used as SDC instance id"); + userInfoMap.put(SdcConsumerInfo.INSTANCE_ID, fragment); + try { + userInfoMap.put(SdcConsumerInfo.CATALOG_URL, new URI(configUri.getScheme(), null, configUri.getHost(), configUri.getPort(), configUri.getPath()+SDC_CATALOG_PATH, null, null).toString()); + } + catch (URISyntaxException se) { + throw new IllegalArgumentException("Invalid uri", se); + } + return userInfoMap; + } + + public static String buildResourceFilterQuery(String resourceType, String category, String subcategory) { + List<String> filters = new ArrayList<>(); + if(!StringUtils.isEmpty(resourceType)) + filters.add("resourceType="+resourceType); + if(!StringUtils.isEmpty(category)) + filters.add("category="+category); + if(!StringUtils.isEmpty(subcategory)) + filters.add("subCategory="+subcategory); + return "?"+filters.stream().collect(Collectors.joining("&")); + } + + public static UserRemarks buildUserRemarksObject(String userRemarks) { + return new UserRemarks(userRemarks); + } + + private static class UserRemarks { + private String userRemarks; + + private UserRemarks(String userRemarks) { + this.userRemarks = userRemarks; + } + + public String getUserRemarks() { + return userRemarks; + } + } + + public static String artifactToString(Artifact artifact) throws JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(artifact); + } + + public static Artifact generateDeploymentArtifact(String description, String name, String type, String label, byte[] payload){ + Artifact artifact = new Artifact(); + artifact.setDescription(description); + artifact.setArtifactName(name); + artifact.setArtifactGroupType(ArtifactGroupType.DEPLOYMENT.name()); + artifact.setArtifactType(type); + artifact.setArtifactLabel(label); + artifact.setPayloadData(Base64Utils.encodeToString(payload)); + return artifact; + } +} |