Specify model at service creation
[sdc.git] / catalog-ui / src / app / models / components / component.ts
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 'use strict';
22
23 import * as _ from "lodash";
24 import {AsdcComment, ArtifactModel, ArtifactGroupModel, IFileDownload, PropertyModel, PropertiesGroup, AttributeModel, AttributesGroup, ComponentInstance,
25     InputModel, DisplayModule, Module, IValidate, RelationshipModel, IMainCategory, RequirementsGroup, CapabilitiesGroup, AdditionalInformationModel,
26     Resource, IAppMenu, OperationModel, Service} from "../../models";
27
28 import {IComponentService} from "../../services/components/component-service";
29 import {CommonUtils} from "../../utils/common-utils";
30 import {QueueUtils} from "../../utils/functions";
31 import {ArtifactGroupType} from "../../utils/constants";
32 import {ComponentMetadata} from "../component-metadata";
33 import {Capability} from "../capability";
34 import {Requirement} from "../requirement";
35 import {Relationship} from "../graph/relationship";
36 import { PolicyInstance } from "app/models/graph/zones/policy-instance";
37 import { GroupInstance } from "../graph/zones/group-instance";
38 import { Metadata } from "app/models/metadata";
39
40
41 // import {}
42 export interface IComponent {
43
44     //---------------------------------------------- API CALLS ----------------------------------------------------//
45
46     //Component API
47     getComponent():ng.IPromise<Component>;
48     updateComponent():ng.IPromise<Component>;
49     createComponentOnServer():ng.IPromise<Component>;
50     changeLifecycleState(state:string, commentObj:AsdcComment):ng.IPromise<Component>;
51     validateName(newName:string):ng.IPromise<IValidate>;
52
53     //Artifacts API
54     addOrUpdateArtifact(artifact:ArtifactModel):ng.IPromise<ArtifactModel>;
55     deleteArtifact(artifactId:string, artifactLabel:string):ng.IPromise<ArtifactModel>;
56     downloadInstanceArtifact(artifactId:string):ng.IPromise<IFileDownload>;
57     downloadArtifact(artifactId:string):ng.IPromise<IFileDownload>;
58
59     //Property API
60     addOrUpdateProperty(property:PropertyModel):ng.IPromise<PropertyModel>;
61     deleteProperty(propertyId:string):ng.IPromise<PropertyModel>;
62
63     //Attribute API
64     deleteAttribute(attributeId:string):ng.IPromise<AttributeModel>;
65     addOrUpdateAttribute(attribute:AttributeModel):ng.IPromise<AttributeModel>;
66
67     //Modules
68     getModuleForDisplay(moduleId:string):ng.IPromise<DisplayModule>;
69     getModuleInstanceForDisplay(componentInstanceId:string, moduleId:string):ng.IPromise<DisplayModule>;
70     updateGroupMetadata(group:Module):ng.IPromise<Module>;
71
72     //---------------------------------------------- HELP FUNCTIONS ----------------------------------------------------//
73
74     getComponentSubType():string;
75     isAlreadyCertified():boolean;
76     isService():boolean;
77     isResource():boolean;
78     isComplex():boolean;
79     getAllVersionsAsSortedArray():Array<any>;
80     getStatus(sdcMenu:IAppMenu):string;
81 }
82
83
84 export abstract class Component implements IComponent {
85
86     //server data
87     public abstract:string;
88     public uniqueId:string;
89     public uuid:string;
90     public invariantUUID:string;
91     public name:string;
92     public version:string;
93     public creationDate:number;
94     public lastUpdateDate:number;
95     public description:string;
96     public lifecycleState:string;
97     public tags:Array<string>;
98     public icon:string;
99     public contactId:string;
100     public allVersions:any;
101     public creatorUserId:string;
102     public creatorFullName:string;
103     public lastUpdaterUserId:string;
104     public lastUpdaterFullName:string;
105     public componentType:string;
106     public deploymentArtifacts:ArtifactGroupModel;
107     public artifacts:ArtifactGroupModel;
108     public toscaArtifacts:ArtifactGroupModel;
109     public interfaceOperations:Array<OperationModel>;
110     public distributionStatus:string;
111     public categories:Array<IMainCategory>;
112     public categoryNormalizedName: string;
113     public subCategoryNormalizedName: string;
114     public componentInstancesProperties:PropertiesGroup;
115     public componentInstancesAttributes:AttributesGroup;
116     public componentInstancesRelations:Array<RelationshipModel>;
117     public componentInstances:Array<ComponentInstance>;
118     public inputs:Array<InputModel>;
119     public capabilities:CapabilitiesGroup;
120     public requirements:RequirementsGroup;
121     public additionalInformation:any;
122     public properties:Array<PropertyModel>;
123     public attributes:Array<AttributeModel>;
124     public highestVersion:boolean;
125     public vendorName:string;
126     public vendorRelease:string;
127     public derivedList:Array<any>;
128     public interfaces:any;
129     public normalizedName:string;
130     public systemName:string;
131     public policies:Array<PolicyInstance>;
132     public groupInstances:Array<GroupInstance>
133     public modules:Array<Module>;
134     //custom properties
135     public componentService:IComponentService;
136     public filterTerm:string;
137     public iconSprite:string;
138     public selectedInstance:ComponentInstance;
139     public mainCategory:string;
140     public subCategory:string;
141     public selectedCategory:string;
142     public showMenu:boolean;
143     public archived:boolean;
144     public vspArchived: boolean;
145     public componentMetadata: ComponentMetadata;
146     public categorySpecificMetadata: Metadata = new Metadata();
147     public derivedFromGenericType: string;
148     public derivedFromGenericVersion: string;
149     public model: Model;
150
151     constructor(componentService:IComponentService, protected $q:ng.IQService, component?:Component) {
152         if (component) {
153             this.abstract = component.abstract;
154             this.uniqueId = component.uniqueId;
155             this.uuid = component.uuid;
156             this.invariantUUID = component.invariantUUID;
157             this.additionalInformation = component.additionalInformation;
158             this.artifacts = new ArtifactGroupModel(component.artifacts);
159             this.toscaArtifacts = new ArtifactGroupModel(component.toscaArtifacts);
160             this.interfaceOperations = component.interfaceOperations;
161             this.contactId = component.contactId;
162             this.categories = component.categories;
163             this.categoryNormalizedName = component.categoryNormalizedName;
164             this.subCategoryNormalizedName = component.subCategoryNormalizedName;
165             this.creatorUserId = component.creatorUserId;
166             this.creationDate = component.creationDate;
167             this.creatorFullName = component.creatorFullName;
168             this.description = component.description;
169             this.icon = component.icon;
170             this.lastUpdateDate = component.lastUpdateDate;
171             this.lastUpdaterUserId = component.lastUpdaterUserId;
172             this.lastUpdaterFullName = component.lastUpdaterFullName;
173             this.lifecycleState = component.lifecycleState;
174             this.componentInstancesRelations = CommonUtils.initComponentInstanceRelations(component.componentInstancesRelations);
175             this.componentInstancesProperties = new PropertiesGroup(component.componentInstancesProperties);
176             this.componentInstancesAttributes = new AttributesGroup(component.componentInstancesAttributes);
177             this.name = component.name;
178             this.version = component.version;
179             this.tags = [];
180             angular.copy(component.tags, this.tags);
181             this.capabilities = new CapabilitiesGroup(component.capabilities);
182             this.requirements = new RequirementsGroup(component.requirements);
183             this.allVersions = component.allVersions;
184             this.deploymentArtifacts = new ArtifactGroupModel(component.deploymentArtifacts);
185             this.componentType = component.componentType;
186             this.distributionStatus = component.distributionStatus;
187             this.highestVersion = component.highestVersion;
188             this.vendorName = component.vendorName;
189             this.vendorRelease = component.vendorRelease;
190             this.derivedList = component.derivedList;
191             this.interfaces = component.interfaces;
192             this.normalizedName = component.normalizedName;
193             this.systemName = component.systemName;
194             this.inputs = component.inputs;
195             this.componentInstances = CommonUtils.initComponentInstances(component.componentInstances);
196             this.properties = CommonUtils.initProperties(component.properties, this.uniqueId);
197             this.attributes = CommonUtils.initAttributes(component.attributes, this.uniqueId);
198             this.selectedInstance = component.selectedInstance;
199             this.iconSprite = component.iconSprite;
200             this.showMenu = true;
201             this.modules = component.modules;
202             this.groupInstances = component.groupInstances;
203             this.policies = component.policies;
204             this.archived = component.archived;
205             this.vspArchived = component.vspArchived;
206
207             if (component.categorySpecificMetadata && component.categories && component.categories[0]){
208                 this.copyCategoryMetadata(component);
209                 this.copySubcategoryMetadata(component);
210             }
211
212             this.derivedFromGenericType = component.derivedFromGenericType;
213             this.derivedFromGenericVersion = component.derivedFromGenericVersion;
214             this.model = component.model;
215         }
216
217         //custom properties
218         this.componentService = componentService;
219     }
220
221     private copyCategoryMetadata = (component:Component):void => {
222         if (component.categories[0].metadataKeys){
223             for (let key of Object.keys(component.categorySpecificMetadata)) {
224                 if (component.categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
225                     this.categorySpecificMetadata[key] = component.categorySpecificMetadata[key];
226                 }
227             }
228         }
229     }
230     private copySubcategoryMetadata = (component:Component):void => {
231         if (component.categories[0].subcategories && component.categories[0].subcategories[0] && component.categories[0].subcategories[0].metadataKeys){
232             for (let key of Object.keys(component.categorySpecificMetadata)) {
233                 if (component.categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) {
234                     this.categorySpecificMetadata[key] = component.categorySpecificMetadata[key];
235                 }
236             }
237         }
238     }
239
240     public setUniqueId = (uniqueId:string):void => {
241         this.uniqueId = uniqueId;
242     };
243
244     //------------------------------------------ API Calls ----------------------------------------------------------------//
245     public changeLifecycleState = (state:string, commentObj:AsdcComment):ng.IPromise<Component> => {
246         let deferred = this.$q.defer<Component>();
247         let onSuccess = (componentMetadata:ComponentMetadata):void => {
248             this.setComponentMetadata(componentMetadata);
249             // this.version = componentMetadata.version;
250             this.lifecycleState = componentMetadata.lifecycleState;
251
252             deferred.resolve(this);
253         };
254         let onError = (error:any):void => {
255             deferred.reject(error);
256         };
257         this.componentService.changeLifecycleState(this, state, commentObj).then(onSuccess, onError);
258         return deferred.promise;
259     };
260
261     public getComponent = ():ng.IPromise<Component> => {
262         return this.componentService.getComponent(this.uniqueId);
263     };
264
265     public createComponentOnServer = ():ng.IPromise<Component> => {
266         this.handleTags();
267         return this.componentService.createComponent(this);
268     };
269     
270     public importComponentOnServer = (): ng.IPromise<Component> => {
271         this.handleTags();
272         return this.componentService.importComponent(this);
273     };
274
275     public updateComponent = ():ng.IPromise<Component> => {
276         this.handleTags();
277         return this.componentService.updateComponent(this);
278     };
279
280     public validateName = (newName:string, subtype?:string):ng.IPromise<IValidate> => {
281         return this.componentService.validateName(newName, subtype);
282     };
283
284     public downloadArtifact = (artifactId: string): ng.IPromise<IFileDownload> => {
285         if(this.vendorName === 'IsService'){
286             return this.componentService.downloadArtifact(this.uniqueId, artifactId, this.vendorName);
287         }else{
288             return this.componentService.downloadArtifact(this.uniqueId, artifactId);
289         }
290     };
291
292     public addOrUpdateArtifact = (artifact:ArtifactModel):ng.IPromise<ArtifactModel> => {
293         let deferred = this.$q.defer<ArtifactModel>();
294         let onSuccess = (artifactObj:ArtifactModel):void => {
295             let newArtifact = new ArtifactModel(artifactObj);
296             let artifacts = this.getArtifactsByType(artifactObj.artifactGroupType);
297             artifacts[artifactObj.artifactLabel] = newArtifact;
298             deferred.resolve(newArtifact);
299         };
300         let onError = (error:any):void => {
301             deferred.reject(error);
302         };
303         this.componentService.addOrUpdateArtifact(this.uniqueId, artifact).then(onSuccess, onError);
304         return deferred.promise;
305     };
306
307     public deleteArtifact = (artifactId:string, artifactLabel:string):ng.IPromise<ArtifactModel> => {
308         let deferred = this.$q.defer<ArtifactModel>();
309         let onSuccess = (artifactObj:ArtifactModel):void => {
310             let newArtifact = new ArtifactModel(artifactObj);
311             let artifacts = this.getArtifactsByType(artifactObj.artifactGroupType);
312             if (newArtifact.mandatory || newArtifact.serviceApi) {
313                 artifacts[newArtifact.artifactLabel] = newArtifact;
314             }
315             else {
316                 delete artifacts[artifactLabel];
317             }
318             deferred.resolve(newArtifact);
319         };
320         this.componentService.deleteArtifact(this.uniqueId, artifactId, artifactLabel).then(onSuccess);
321         return deferred.promise;
322     };
323
324     public addOrUpdateProperty = (property:PropertyModel):ng.IPromise<PropertyModel> => {
325         let deferred = this.$q.defer<PropertyModel>();
326
327         let onError = (error:any):void => {
328             deferred.reject(error);
329         };
330
331         if (!property.uniqueId) {
332             let onSuccess = (property:PropertyModel):void => {
333                 let newProperty = new PropertyModel(property);
334                 this.properties.push(newProperty);
335                 deferred.resolve(newProperty);
336             };
337             this.componentService.addProperty(this.uniqueId, property).then(onSuccess, onError);
338         }
339         else {
340             let onSuccess = (newProperty:PropertyModel):void => {
341                 // find exist instance property in parent component for update the new value ( find bu uniqueId )
342                 let existProperty:PropertyModel = <PropertyModel>_.find(this.properties, {uniqueId: newProperty.uniqueId});
343                 let propertyIndex = this.properties.indexOf(existProperty);
344                 this.properties[propertyIndex] = newProperty;
345                 deferred.resolve(newProperty);
346             };
347             this.componentService.updateProperty(this.uniqueId, property).then(onSuccess, onError);
348         }
349         return deferred.promise;
350     };
351
352     public addOrUpdateAttribute = (attribute:AttributeModel):ng.IPromise<AttributeModel> => {
353         let deferred = this.$q.defer<AttributeModel>();
354
355         let onError = (error:any):void => {
356             deferred.reject(error);
357         };
358
359         if (!attribute.uniqueId) {
360             let onSuccess = (attribute:AttributeModel):void => {
361                 let newAttribute = new AttributeModel(attribute);
362                 this.attributes.push(newAttribute);
363                 deferred.resolve(newAttribute);
364             };
365             this.componentService.addAttribute(this.uniqueId, attribute).then(onSuccess, onError);
366         }
367         else {
368             let onSuccess = (newAttribute:AttributeModel):void => {
369                 let existAttribute:AttributeModel = <AttributeModel>_.find(this.attributes, {uniqueId: newAttribute.uniqueId});
370                 let attributeIndex = this.attributes.indexOf(existAttribute);
371                 newAttribute.readonly = this.uniqueId != newAttribute.parentUniqueId;
372                 this.attributes[attributeIndex] = newAttribute;
373                 deferred.resolve(newAttribute);
374             };
375             this.componentService.updateAttribute(this.uniqueId, attribute).then(onSuccess, onError);
376         }
377         return deferred.promise;
378     };
379
380     public deleteProperty = (propertyId:string):ng.IPromise<PropertyModel> => {
381         let deferred = this.$q.defer<PropertyModel>();
382         let onSuccess = ():void => {
383             console.log("Property deleted");
384             delete _.remove(this.properties, {uniqueId: propertyId})[0];
385             deferred.resolve();
386         };
387         let onFailed = ():void => {
388             console.log("Failed to delete property");
389             deferred.reject();
390         };
391         this.componentService.deleteProperty(this.uniqueId, propertyId).then(onSuccess, onFailed);
392         return deferred.promise;
393     };
394
395     public deleteAttribute = (attributeId:string):ng.IPromise<AttributeModel> => {
396         let deferred = this.$q.defer<AttributeModel>();
397         let onSuccess = ():void => {
398             console.log("Attribute deleted");
399             delete _.remove(this.attributes, {uniqueId: attributeId})[0];
400         };
401         let onFailed = ():void => {
402             console.log("Failed to delete attribute");
403         };
404         this.componentService.deleteAttribute(this.uniqueId, attributeId).then(onSuccess, onFailed);
405         return deferred.promise;
406     };
407
408     public downloadInstanceArtifact = (artifactId:string):ng.IPromise<IFileDownload> => {
409         return this.componentService.downloadInstanceArtifact(this.uniqueId, this.selectedInstance.uniqueId, artifactId);
410     };
411
412     public getModuleForDisplay = (moduleId:string):ng.IPromise<DisplayModule> => {
413
414         let deferred = this.$q.defer<DisplayModule>();
415         let onSuccess = (response:DisplayModule):void => {
416             deferred.resolve(response);
417         };
418         let onFailed = (error:any):void => {
419             deferred.reject(error);
420         };
421         this.componentService.getModuleForDisplay(this.uniqueId, moduleId).then(onSuccess, onFailed);
422         return deferred.promise;
423     };
424
425     public getModuleInstanceForDisplay = (componentInstanceId:string, moduleId:string):ng.IPromise<DisplayModule> => {
426
427         let deferred = this.$q.defer<DisplayModule>();
428         let onSuccess = (response:DisplayModule):void => {
429             deferred.resolve(response);
430         };
431         let onFailed = (error:any):void => {
432             deferred.reject(error);
433         };
434         this.componentService.getComponentInstanceModule(this.uniqueId, componentInstanceId, moduleId).then(onSuccess, onFailed);
435         return deferred.promise;
436     };
437
438     public updateGroupMetadata = (module:Module):ng.IPromise<Module> => {
439
440         let deferred = this.$q.defer<Module>();
441
442         let onSuccess = (updatedModule:Module):void => {
443             let groupIndex:number = _.indexOf(this.modules, _.find(this.modules, (module:Module) => {
444                 return module.uniqueId === updatedModule.uniqueId;
445             }));
446
447             if (groupIndex !== -1) {
448                 this.modules[groupIndex] = updatedModule;
449             }
450             deferred.resolve(updatedModule);
451         };
452         let onFailed = (error:any):void => {
453             deferred.reject(error);
454         };
455
456         this.componentService.updateGroupMetadata(this.uniqueId, module).then(onSuccess, onFailed);
457
458         return deferred.promise;
459     };
460
461     //------------------------------------------ Help Functions ----------------------------------------------------------------//
462
463     public isService = ():boolean => {
464         return this instanceof Service;
465     };
466
467     public isResource = ():boolean => {
468         return this instanceof Resource;
469     };
470
471     public getComponentSubType = ():string => {
472         return this.componentType;
473     };
474
475     public isAlreadyCertified = ():boolean => {
476         return parseInt(this.version) >= 1;
477     };
478
479     public isComplex = ():boolean => {
480         return true;
481     };
482
483     //sort string version value from hash to sorted version (i.e 1.9 before 1.11)
484     private sortVersions = (v1:string, v2:string):number => {
485         let ver1 = v1.split('.');
486         let ver2 = v2.split('.');
487         let diff = parseInt(_.first(ver1)) - parseInt(_.first(ver2));
488         if (!diff) {
489             return parseInt(_.last(ver1)) - parseInt(_.last(ver2));
490         }
491         return diff;
492     };
493
494     public getAllVersionsAsSortedArray = ():Array<any> => {
495         let res = [];
496         if (this.allVersions) {
497             let keys = Object.keys(this.allVersions).sort(this.sortVersions);
498             _.forEach(keys, (key)=> {
499                 res.push({
500                     versionNumber: key,
501                     versionId: this.allVersions[key]
502                 })
503             });
504         }
505         return res;
506     };
507
508     public isLatestVersion = ():boolean => {
509         if (this.allVersions) {
510             return this.version === _.last(Object.keys(this.allVersions).sort(this.sortVersions));
511         } else {
512             return true;
513         }
514
515     };
516
517
518     public handleTags = ():void => {
519         let isContainTag = _.find(this.tags, (tag)=> {
520             return tag === this.name;
521         });
522         if (!isContainTag) {
523             this.tags.push(this.name);
524         }
525     };
526
527     public getArtifactsByType = (artifactGroupType:string):ArtifactGroupModel => {
528         switch (artifactGroupType) {
529             case ArtifactGroupType.DEPLOYMENT:
530                 return this.deploymentArtifacts;
531             case ArtifactGroupType.INFORMATION:
532                 return this.artifacts;
533         }
534     };
535
536     public getStatus = (sdcMenu:IAppMenu):string => {
537         let status:string = sdcMenu.LifeCycleStatuses[this.lifecycleState].text;
538         if (this.lifecycleState == "CERTIFIED" && sdcMenu.DistributionStatuses[this.distributionStatus]) {
539             status = sdcMenu.DistributionStatuses[this.distributionStatus].text;
540         }
541         return status;
542     };
543
544     public abstract setComponentDisplayData():void;
545     public abstract getTypeUrl():string;
546
547     public setComponentMetadata(componentMetadata: ComponentMetadata) {
548         this.abstract = componentMetadata.abstract;
549         this.uniqueId = componentMetadata.uniqueId;
550         this.uuid = componentMetadata.uuid;
551         this.invariantUUID = componentMetadata.invariantUUID;
552         this.contactId = componentMetadata.contactId;
553         this.categories = componentMetadata.categories;
554         this.creatorUserId = componentMetadata.creatorUserId;
555         this.creationDate = componentMetadata.creationDate;
556         this.creatorFullName = componentMetadata.creatorFullName;
557         this.description = componentMetadata.description;
558         this.icon = componentMetadata.icon;
559         this.lastUpdateDate = componentMetadata.lastUpdateDate;
560         this.lastUpdaterUserId = componentMetadata.lastUpdaterUserId;
561         this.lastUpdaterFullName = componentMetadata.lastUpdaterFullName;
562         this.lifecycleState = componentMetadata.lifecycleState;
563         this.name = componentMetadata.name;
564         this.version = componentMetadata.version;
565         this.tags = angular.copy(componentMetadata.tags, this.tags);
566         this.allVersions = componentMetadata.allVersions;
567         this.componentType = componentMetadata.componentType;
568         this.distributionStatus = componentMetadata.distributionStatus;
569         this.highestVersion = componentMetadata.highestVersion;
570         this.vendorName = componentMetadata.vendorName;
571         this.vendorRelease = componentMetadata.vendorRelease;
572         this.derivedList = componentMetadata.derivedList;
573         this.normalizedName = componentMetadata.normalizedName;
574         this.systemName = componentMetadata.systemName;
575         this.categories = componentMetadata.categories;
576         this.archived = componentMetadata.archived || false;
577         this.vspArchived = componentMetadata.vspArchived;
578         this.componentMetadata = componentMetadata;
579         if (componentMetadata.categorySpecificMetadata){
580             this.categorySpecificMetadata = componentMetadata.categorySpecificMetadata;
581         } else {
582             this.categorySpecificMetadata = new Metadata();
583         }
584     }
585
586     public toJSON = ():any => {
587         let temp = angular.copy(this);
588         temp.componentService = undefined;
589         temp.filterTerm = undefined;
590         temp.iconSprite = undefined;
591         temp.mainCategory = undefined;
592         temp.subCategory = undefined;
593         temp.selectedInstance = undefined;
594         temp.showMenu = undefined;
595         temp.$q = undefined;
596         temp.selectedCategory = undefined;
597         temp.modules = undefined
598         temp.groupInstances = undefined;
599         temp.policies = undefined;
600         return temp;
601     };
602 }
603