aboutsummaryrefslogtreecommitdiffstats
path: root/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery
diff options
context:
space:
mode:
authorhuangjian <huang.jian12@zte.com.cn>2016-08-31 16:47:33 +0800
committerhuangjian <huang.jian12@zte.com.cn>2016-08-31 16:47:33 +0800
commitfa49e78cc199526a9e33b59c5194f8e3bf0f0952 (patch)
tree3478e867a8f304266dbceca6e992cceca410ede4 /winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery
parent159d40f0011559c8f82338b29dca1bffd700f2c8 (diff)
Add winery source code
Change-Id: I1c5088121d79b71098c3cba1996c6f784737532e Issue-id: TOSCA-49 Signed-off-by: huangjian <huang.jian12@zte.com.cn>
Diffstat (limited to 'winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery')
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java34
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java67
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java138
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java332
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java787
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java110
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java995
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java189
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java68
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java43
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java30
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java19
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java84
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java47
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java25
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java72
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java110
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java596
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java190
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java27
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java33
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java110
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java60
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java30
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java55
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java22
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java28
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java24
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java28
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java56
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java52
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java65
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java17
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java299
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java43
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java38
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java67
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java802
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java1158
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java81
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java24
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java107
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java20
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java516
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java200
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java52
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java279
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java71
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java69
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java39
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java92
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java103
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java123
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java43
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java39
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java19
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java23
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java19
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java74
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java189
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java38
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java24
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java42
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java206
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java123
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java20
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java66
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java29
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java114
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java33
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java36
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java17
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java45
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java57
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java253
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java112
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java204
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java25
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java29
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java28
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java87
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java73
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java42
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java572
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java95
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java93
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java43
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java60
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java34
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java66
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java92
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java30
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java308
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java21
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java163
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java27
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java95
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java23
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java29
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java105
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java18
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java19
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java81
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java18
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java74
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java133
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java23
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java67
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java90
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java47
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java22
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java101
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java105
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java22
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java84
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java177
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java92
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java50
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java89
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java45
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java131
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java17
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java41
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java28
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java66
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java22
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java85
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java161
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java41
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java59
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java132
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java95
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java165
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java17
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java291
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java83
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java44
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java22
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java44
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java133
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java38
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java174
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java124
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java46
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java140
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java71
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java69
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java62
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java99
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java27
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java263
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java18
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java113
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java144
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java115
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java34
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java249
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java38
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java38
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java16
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java46
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java16
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java76
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java85
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java18
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java115
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java203
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java205
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java136
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java96
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java131
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java223
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java145
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java39
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java26
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java39
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java280
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java38
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java30
-rw-r--r--winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java16
188 files changed, 19774 insertions, 0 deletions
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java
new file mode 100644
index 0000000..966b5f2
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/CORSFilter.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+
+import com.sun.jersey.spi.container.ContainerRequest;
+import com.sun.jersey.spi.container.ContainerResponse;
+import com.sun.jersey.spi.container.ContainerResponseFilter;
+
+/**
+ * Required for the BPMN4TOSCA modeler when not running on the same machine
+ */
+public class CORSFilter implements ContainerResponseFilter {
+
+ @Override
+ public ContainerResponse filter(ContainerRequest containerRequest, ContainerResponse containerResponse) {
+ ResponseBuilder response = Response.fromResponse(containerResponse.getResponse());
+ response.header("Access-Control-Allow-Origin", "*").header("Access-Control-Allow-Methods", "GET, PUT, OPTIONS");
+ containerResponse.setResponse(response.build());
+ return containerResponse;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java
new file mode 100644
index 0000000..60eacdd
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Constants.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public class Constants {
+
+ /** repository specific **/
+ public static final String DEFAULT_REPO_NAME = "winery-repository";
+ // this directory is checked for existence. If it does not exist
+ // $HOME/DEFAULT_REPO_NAME is used
+ public static final String GLOBAL_REPO_PATH_WINDOWS = "C:\\" + Constants.DEFAULT_REPO_NAME;
+
+ /** file-system in general **/
+ public static final String newline = System.getProperty("line.separator");
+
+ // Path to images for extensions
+ // Currently, we require the format <filenamextension>.png
+ public static final String PATH_MIMETYPEIMAGES = "/images/mime-types/";
+
+ // suffix for BPMN4TOSCA
+ public static final String SUFFIX_BPMN4TOSCA = ".bpmn4tosca";
+
+ // suffix for CSAR files
+ public static final String SUFFIX_CSAR = ".csar";
+
+ // suffix for files in the directory PATH_MIMETYPEIMAGES, including "."
+ public static final String SUFFIX_MIMETYPEIMAGES = ".png";
+
+ // suffix for files storing the mimetype of the belonging files
+ // used in implementors if IRepository of no appropriate implementation for storing a mimetype is available
+ public static final String SUFFIX_MIMETYPE = ".mimetype";
+
+ // suffix for all property files
+ public static final String SUFFIX_PROPERTIES = ".properties";
+
+ // suffix for all files storing Definitions
+ // following line 2935 of TOSCA cos01
+ public static final String SUFFIX_TOSCA_DEFINITIONS = ".tosca";
+
+ // at each new start of the application, the modified date changes
+ // reason: the default values of the properties or the JSP could have
+ // changed
+ public static final Date LASTMODIFIEDDATE_FOR_404 = Calendar.getInstance().getTime();
+
+ public static final String TOSCA_PLANTYPE_BUILD_PLAN = "http://docs.oasis-open.org/tosca/ns/2011/12/PlanTypes/BuildPlan";
+ public static final String TOSCA_PLANTYPE_TERMINATION_PLAN = "http://docs.oasis-open.org/tosca/ns/2011/12/PlanTypes/TerminationPlan";
+
+ public static final String DIRNAME_SELF_SERVICE_METADATA = "SELFSERVICE-Metadata";
+
+ /* used for IA generation */
+ //public static final String NAMESPACE_ARTIFACTTYPE_WAR = "http://www.opentosca.org/types";
+ public static final String NAMESPACE_ARTIFACTTYPE_WAR = "http://www.example.com/ToscaTypes";
+ public static final String LOCALNAME_ARTIFACTTYPE_WAR = "WAR";
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java
new file mode 100644
index 0000000..876c015
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/JAXBSupport.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.tosca.TDefinitions;
+import org.eclipse.winery.repository.backend.MockXMLElement;
+import org.eclipse.winery.repository.resources.admin.NamespacesResource;
+import org.eclipse.winery.model.selfservice.Application;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
+
+// if com.sun.xml.bind.marshaller.NamespacePrefixMapper cannot be resolved,
+// possibly
+// http://mvnrepository.com/artifact/com.googlecode.jaxb-namespaceprefixmapper-interfaces/JAXBNamespacePrefixMapper/2.2.4
+// helps
+// also com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper could be the
+// right package
+
+/**
+ * Bundles all general JAXB functionality
+ */
+public class JAXBSupport {
+
+ private static final Logger logger = LoggerFactory.getLogger(JAXBSupport.class);
+
+ // thread-safe JAXB as inspired by https://jaxb.java.net/guide/Performance_and_thread_safety.html
+ // The other possibility: Each subclass sets JAXBContext.newInstance(theSubClass.class); in its static {} part.
+ // This seems to be more complicated than listing all subclasses in initContext
+ public final static JAXBContext context = JAXBSupport.initContext();
+
+ private final static PrefixMapper prefixMapper = new PrefixMapper();
+
+
+ /**
+ * Follows
+ * https://jaxb.java.net/2.2.5/docs/release-documentation.html#marshalling
+ * -changing-prefixes
+ *
+ * See http://www.jarvana.com/jarvana/view/com/sun/xml/bind/jaxb-impl/2.2.2/
+ * jaxb-impl-2.2.2-javadoc.jar!/com/sun/xml/bind/marshaller/
+ * NamespacePrefixMapper.html for a JavaDoc of the NamespacePrefixMapper
+ */
+ private static class PrefixMapper extends NamespacePrefixMapper {
+
+ @Override
+ public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
+ if (namespaceUri.equals("")) {
+ return "";
+ }
+
+ // this does not work to get TOSCA elements without prefix
+ // possibly because the attribute "name" is present without prefix
+ // if (namespaceUri.equals(Namespaces.TOSCA_NAMESPACE)) {
+ // return "";
+ // }
+
+ String prefix = NamespacesResource.getPrefix(namespaceUri);
+ return prefix;
+ }
+ }
+
+
+ private static JAXBContext initContext() {
+ JAXBContext context;
+ try {
+ // For winery classes, eventually the package+jaxb.index method could be better. See http://stackoverflow.com/a/3628525/873282
+ // @formatter:off
+ context = JAXBContext.newInstance(
+ TDefinitions.class, // all other elements are referred by "@XmlSeeAlso"
+ WinerysPropertiesDefinition.class,
+ // for the self-service portal
+ Application.class,
+ // MockXMLElement is added for testing purposes only.
+ MockXMLElement.class);
+ // @formatter:on
+ } catch (JAXBException e) {
+ JAXBSupport.logger.error("Could not initialize JAXBContext", e);
+ throw new IllegalStateException(e);
+ }
+ return context;
+ }
+
+ /**
+ * Creates a marshaller
+ *
+ * @throws IllegalStateException if marshaller could not be instantiated
+ */
+ public static Marshaller createMarshaller(boolean includeProcessingInstruction) {
+ Marshaller m;
+ try {
+ m = JAXBSupport.context.createMarshaller();
+ // pretty printed output is required as the XML is sent 1:1 to the browser for editing
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ m.setProperty("com.sun.xml.bind.namespacePrefixMapper", JAXBSupport.prefixMapper);
+ if (!includeProcessingInstruction) {
+ // side effect of JAXB_FRAGMENT property (when true): processing instruction is not included
+ m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
+ }
+ } catch (JAXBException e) {
+ JAXBSupport.logger.error("Could not instantiate marshaller", e);
+ throw new IllegalStateException(e);
+ }
+
+ return m;
+ }
+
+ /**
+ * Creates an unmarshaller
+ *
+ * @throws IllegalStateException if unmarshaller could not be instantiated
+ */
+ public static Unmarshaller createUnmarshaller() {
+ try {
+ return JAXBSupport.context.createUnmarshaller();
+ } catch (JAXBException e) {
+ JAXBSupport.logger.error("Could not instantiate unmarshaller", e);
+ throw new IllegalStateException(e);
+ }
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java
new file mode 100644
index 0000000..cbb120f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Prefs.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ * C. Timurhan Sungur - jClouds preferences
+ *******************************************************************************/
+package org.eclipse.winery.repository;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessControlException;
+import java.util.Locale;
+import java.util.Properties;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.eclipse.winery.common.TOSCADocumentBuilderFactory;
+import org.eclipse.winery.repository.backend.IRepository;
+import org.eclipse.winery.repository.backend.filebased.FilebasedRepository;
+import org.eclipse.winery.repository.backend.filebased.GitBasedRepository;
+import org.eclipse.winery.repository.runtimeintegration.OpenTOSCAContainerConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Prefs implements ServletContextListener {
+
+ // set by the constructors
+ // We have to do this hack as the servlet container initializes this class
+ // on its own and we want to have a *single* instance of this class.
+ public static Prefs INSTANCE;
+
+ private static final Logger logger = LoggerFactory.getLogger(Prefs.class);
+
+ protected IRepository repository = null;
+
+ private ServletContext context;
+
+ private Boolean isContainerLocallyAvailable = null;
+
+ private Boolean isRestDocDocumentationAvailable = null;
+
+ private Boolean isPlanBuilderAvailable = null;
+
+ // location of the winery topology modeler
+ private String wineryTopologyModelerPath = null;
+
+ // the properties from winery.properties
+ protected Properties properties = null;
+
+ // package visibility to ease testing
+ static final String PROP_JCLOUDS_CONTEXT_PROVIDER = "jclouds.context.provider";
+ static final String PROP_JCLOUDS_CONTEXT_IDENTITY = "jclouds.context.identity";
+ static final String PROP_JCLOUDS_CONTEXT_CREDENTIAL = "jclouds.context.credential";
+ static final String PROP_JCLOUDS_BLOBSTORE_LOCATION = "jclouds.blobstore.location";
+ static final String PROP_JCLOUDS_CONTAINERNAME = "jclouds.blobstore.container";
+ static final String PROP_JCLOUDS_END_POINT = "jclouds.blobstore.endpoint";
+
+ static final String PROP_BPMN4TOSCA_MODELER_URI = "bpmn4toscamodelerBaseURI";
+
+
+ /**
+ * This constructor is called at handling at servlets, too. Therefore, we
+ * make it private. If testing is needed, an additional paramater has to be
+ * passed
+ */
+ public Prefs() {
+ Prefs.INSTANCE = this;
+ }
+
+ /**
+ * Constructor for Unit testing ONLY!
+ *
+ * @param initializeRepository true if the repository should be initialized
+ * as provided in winery.properties
+ * @throws IOException
+ * @warning Do not call! (except from Unit testing code)
+ */
+ protected Prefs(boolean initializeRepository) throws IOException {
+ this();
+
+ // emulate behavior of doInitialization(Context)
+ Properties p = new Properties();
+ InputStream is = this.getClass().getClassLoader().getResourceAsStream("winery.properties");
+ if (is != null) {
+ p.load(is);
+ }
+ this.properties = p;
+
+ if (initializeRepository) {
+ this.doRepositoryInitialization();
+ }
+ }
+
+ /**
+ * Initialization code for the repository. Should go into separate class,
+ * but being here should be OK for a prototype
+ *
+ * Called from both the constructor for JUnit and the servlet-based
+ * initialization
+ *
+ * Pre-Condition: this.properties is set.
+ */
+ private void doRepositoryInitialization() {
+ assert (this.properties != null);
+
+ String provider = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_PROVIDER);
+ if (provider != null) {
+ // repository runs via jclouds
+ // String identity = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_IDENTITY);
+ // String credential = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTEXT_CREDENTIAL);
+ // String location = this.properties.getProperty(Prefs.PROP_JCLOUDS_BLOBSTORE_LOCATION);
+ // String containerName = this.properties.getProperty(Prefs.PROP_JCLOUDS_CONTAINERNAME);
+ // String endPoint = this.properties.getProperty(Prefs.PROP_JCLOUDS_END_POINT);
+ Prefs.logger.error("jClouds is currently not supported due to jClouds not yet approved by Eclipse. Falling back to local storages");
+ provider = null;
+ // Prefs.logger.info("Using jclouds as interface to the repository");
+ // this.repository = new JCloudsBasedRepository(provider, identity, credential, location, containerName, endPoint);
+ } // else {
+ if (provider == null) {
+ String repositoryLocation = this.properties.getProperty("repositoryPath");
+ Prefs.logger.debug("Repository location: {}", repositoryLocation);
+ Prefs.logger.debug("Trying git-based backend");
+ try {
+ this.repository = new GitBasedRepository(repositoryLocation);
+ Prefs.logger.debug("git-based backend is used");
+ } catch (Throwable e) {
+ Prefs.logger.trace(e.getMessage());
+ Prefs.logger.debug("There seems to be no git repository at the specified location. We fall back to the file-based repository");
+ this.repository = new FilebasedRepository(repositoryLocation);
+ }
+ }
+ }
+
+ private void doInitialization(ServletContext ctx) {
+ if (Locale.getDefault() != Locale.ENGLISH) {
+ try {
+ // needed for {@link
+ // org.eclipse.winery.repository.filesystem.Utils.returnFile(File,
+ // String)}
+ Locale.setDefault(Locale.ENGLISH);
+ } catch (AccessControlException e) {
+ // Happens at Google App Engine
+ Prefs.logger.error("Could not switch locale to English", e);
+ }
+ }
+
+ this.context = ctx;
+
+ // Reading //
+ final String fn = "/WEB-INF/classes/winery.properties";
+ Prefs.logger.debug("Trying to read ".concat(ctx.getRealPath(fn)));
+ InputStream inStream = ctx.getResourceAsStream(fn);
+ // alternative: InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("winery.properties");
+ Properties p = new Properties();
+ if (inStream == null) {
+ Prefs.logger.info(fn + " does not exist.");
+
+ // We search for winery.properties on the filesystem in the repository
+
+ File propFile = new File(FilebasedRepository.getDefaultRepositoryFilePath(), "winery.properties");
+ Prefs.logger.info("Trying " + propFile.getAbsolutePath());
+ if (propFile.exists()) {
+ Prefs.logger.info("Found");
+ // if winery.property exists in the root of the default repository path (~/winery-repository), load it
+ try (InputStream is2 = new FileInputStream(propFile)) {
+ p.load(is2);
+ } catch (IOException e) {
+ Prefs.logger.error("Could not load winery.properties", e);
+ }
+ } else {
+ Prefs.logger.info("Not found");
+ }
+ } else {
+ try {
+ p.load(inStream);
+ try {
+ inStream.close();
+ } catch (IOException e) {
+ Prefs.logger.error("Could not close stream of winery.properties", e);
+ }
+ } catch (FileNotFoundException e) {
+ // OK if file does not exist
+ } catch (IOException e) {
+ Prefs.logger.error("Could not load winery.properties", e);
+ }
+ }
+
+ this.wineryTopologyModelerPath = p.getProperty("topologymodeler");
+
+ // make the properties known in the class
+ this.properties = p;
+
+ this.doRepositoryInitialization();
+
+ // Initialize XSD validation in the background. Takes up a few seconds.
+ // If we do not do it here, the first save by a user takes a few seconds, which is inconvenient
+ new Thread() {
+
+ @Override
+ public void run() {
+ Prefs.logger.debug("Initializing XML validation");
+ @SuppressWarnings("unused")
+ TOSCADocumentBuilderFactory tdbf = TOSCADocumentBuilderFactory.INSTANCE;
+ Prefs.logger.debug("Initialized XML validation");
+ }
+ }.start();
+ }
+
+ public IRepository getRepository() {
+ return this.repository;
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent arg0) {
+ Prefs.INSTANCE.doInitialization(arg0.getServletContext());
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent arg0) {
+ // nothing to do at tear down
+ }
+
+ /**
+ * @return the path of the root resource
+ */
+ public String getResourcePath() {
+ return this.context.getContextPath();
+ }
+
+ /**
+ * @return the path to the winery topology modeler. Without trailing slash
+ */
+ public String getWineryTopologyModelerPath() {
+ if (this.wineryTopologyModelerPath == null) {
+ // derive the path from the current path
+ String res = this.getResourcePath();
+ if (res.endsWith("/")) {
+ res = res.substring(0, res.length() - 1);
+ }
+ int pos = res.lastIndexOf("/");
+ if (pos <= 0) {
+ res = "/winery-topologymodeler";
+ } else {
+ res = res.substring(0, pos);
+ res = res + "winery-topologymodeler";
+ }
+ return res;
+ } else {
+ assert (this.wineryTopologyModelerPath != null);
+ return this.wineryTopologyModelerPath;
+ }
+ }
+
+ /**
+ * Returns the read content from winery.properties.
+ *
+ * @return the internal object held by this class. Manipulations on this
+ * object may cause trouble.
+ */
+ public Properties getProperties() {
+ return this.properties;
+ }
+
+ /**
+ * @return the version of winery
+ */
+ public String getVersion() {
+ return Version.VERSION;
+ }
+
+ /**
+ * @return true if the OpenTOSCA container is locally available
+ */
+ public boolean isContainerLocallyAvailable() {
+ if (this.isContainerLocallyAvailable == null) {
+ // we initialize the variable at the first read
+ // The container and Winery are started simultaneously
+ // Therefore, the container might not be available if Winery is starting
+ // When checking at the first read, chances are high that the container started
+ this.isContainerLocallyAvailable = OpenTOSCAContainerConnection.isContainerLocallyAvailable();
+ }
+ return this.isContainerLocallyAvailable;
+ }
+
+ /**
+ * @return true if the plan generator is available
+ */
+ public boolean isPlanBuilderAvailable() {
+ // similar implementation as isContainerLocallyAvailable()
+ if (this.isPlanBuilderAvailable == null) {
+ String planBuilderURI = "http://localhost:1339/planbuilder";
+ this.isPlanBuilderAvailable = Utils.isResourceAvailable(planBuilderURI);
+ }
+ return this.isPlanBuilderAvailable;
+ }
+
+ /**
+ * Quick hack to check whether a RestDoc documentation is available at
+ * /restdoc.html. We do not deliver
+ */
+ public boolean isRestDocDocumentationAvailable() {
+ String path = "http://localhost:8080/restdoc.html";
+ if (this.isRestDocDocumentationAvailable == null) {
+ // we initialize the variable at the first read
+ // The container and Winery are started simultaneously
+ // Therefore, the container might not be available if Winery is starting
+ // When checking at the first read, chances are high that the container started
+ this.isRestDocDocumentationAvailable = Utils.isResourceAvailable(path);
+ }
+ return this.isRestDocDocumentationAvailable;
+ }
+
+ /**
+ * @return the base URL of the BPMN4TOSCA plan modeler. NULL if not
+ * configured. May also be empty.
+ */
+ public String getBPMN4TOSCABaseURL() {
+ return this.properties.getProperty(Prefs.PROP_BPMN4TOSCA_MODELER_URI);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java
new file mode 100644
index 0000000..12d84e9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/RestDocFilter.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.winery.repository;
+
+import org.eclipse.winery.repository.resources.MainResource;
+import org.restdoc.jersey.server.RestDocFeature;
+
+public class RestDocFilter extends RestDocFeature {
+
+ @Override
+ protected Class<?>[] getClasses() {
+ Class<?>[] res = {MainResource.class};
+ return res;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java
new file mode 100644
index 0000000..e989324
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/Utils.java
@@ -0,0 +1,787 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.Response.Status.Family;
+import javax.ws.rs.core.StreamingOutput;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+
+import org.apache.taglibs.standard.functions.Functions;
+import org.apache.tika.detect.Detector;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.parser.AutoDetectParser;
+import org.apache.xerces.xs.XSConstants;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.definitions.imports.XSDImportId;
+import org.eclipse.winery.model.tosca.TArtifactType;
+import org.eclipse.winery.model.tosca.TConstraint;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TNodeType;
+import org.eclipse.winery.model.tosca.TPolicyType;
+import org.eclipse.winery.model.tosca.TRelationshipType;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.admin.AdminId;
+import org.eclipse.winery.repository.export.CSARExporter;
+import org.eclipse.winery.repository.export.TOSCAExportUtil;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource;
+import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportResource;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+import org.w3c.dom.Element;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+
+/**
+ * Contains utility functionality concerning with everything that is
+ * <em>not</em> related only to the repository, but more. For instance, resource
+ * functionality. Utility functionality for the repository is contained at
+ * {@link BackendUtils}
+ */
+public class Utils {
+
+ private static final XLogger logger = XLoggerFactory.getXLogger(Utils.class);
+
+
+ public static URI createURI(String uri) {
+ try {
+ return new URI(uri);
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException();
+ }
+ }
+
+
+ // RegExp inspired by http://stackoverflow.com/a/5396246/873282
+ // NameStartChar without ":"
+ // stackoverflow: -dfff, standard: d7fff
+ private static final String RANGE_NCNAMESTARTCHAR = "A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d" + "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff" + "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\x10000-\\xEFFFF";
+ private static final String REGEX_NCNAMESTARTCHAR = "[" + Utils.RANGE_NCNAMESTARTCHAR + "]";
+
+ private static final String RANGE_NCNAMECHAR = Utils.RANGE_NCNAMESTARTCHAR + "\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040";
+ private static final String REGEX_INVALIDNCNAMESCHAR = "[^" + Utils.RANGE_NCNAMECHAR + "]";
+
+
+ /**
+ * Creates a (valid) XML ID (NCName) based on the passed name
+ *
+ * Valid NCNames: http://www.w3.org/TR/REC-xml-names/#NT-NCName /
+ * http://www.w3.org/TR/xml/#NT-Name http://www.w3.org/TR/xml/#NT-Name
+ *
+ */
+ public static XMLId createXMLid(String name) {
+ return new XMLId(Utils.createXMLidAsString(name), false);
+ }
+
+ /**
+ * Creates a (valid) XML ID (NCName) based on the passed name
+ *
+ * Valid NCNames: http://www.w3.org/TR/REC-xml-names/#NT-NCName /
+ * http://www.w3.org/TR/xml/#NT-Name http://www.w3.org/TR/xml/#NT-Name
+ *
+ * TODO: this method seems to be equal to {@link
+ * org.eclipse.winery.common.Util.makeNCName(String)}. The methods should be
+ * merged into one.
+ *
+ */
+ public static String createXMLidAsString(String name) {
+ String id = name;
+ if (!id.substring(0, 1).matches(Utils.REGEX_NCNAMESTARTCHAR)) {
+ id = "_".concat(id);
+ }
+ // id starts with a valid character
+
+ // before we wipe out all invalid characters, we do a readable
+ // replacement for appropriate characters
+ id = id.replace(' ', '_');
+
+ // keep length of ID, only wipe out invalid characters
+ // alternative: replace invalid characters by URLencoded version. As the
+ // ID is visible only in the URL, this quick hack should be OK
+ // ID is visible only in the URL, this quick hack should be OK
+ id = id.replaceAll(Utils.REGEX_INVALIDNCNAMESCHAR, "_");
+
+ return id;
+ }
+
+ /**
+ * Returns the plain XML for the selected resource
+ *
+ * @param uri
+ */
+ public static Response getDefinitionsOfSelectedResource(final AbstractComponentInstanceResource resource, final URI uri) {
+ final TOSCAExportUtil exporter = new TOSCAExportUtil();
+ StreamingOutput so = new StreamingOutput() {
+
+ @Override
+ public void write(OutputStream output) throws IOException, WebApplicationException {
+ Map<String, Object> conf = new HashMap<>();
+ conf.put(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString(), uri);
+ try {
+ exporter.exportTOSCA(resource.getId(), output, conf);
+ } catch (JAXBException e) {
+ throw new WebApplicationException(e);
+ }
+ output.close();
+ }
+ };
+ /*
+ * this code is for offering a download action // Browser offers save as
+ * // .tosca is more or less needed for debugging, only a CSAR makes
+ * sense. // Therefore, we want to have the xml opened in the browser.
+ * StringBuilder sb = new StringBuilder();
+ * sb.append("attachment;filename=\"");
+ * sb.append(resource.getXmlId().getEncoded()); sb.append(" - ");
+ * sb.append(resource.getNamespace().getEncoded()); sb.append(".xml");
+ * sb.append("\""); return Response.ok().header("Content-Disposition",
+ * sb
+ * .toString()).type(MediaType.APPLICATION_XML_TYPE).entity(so).build();
+ */
+ return Response.ok().type(MediaType.APPLICATION_XML).entity(so).build();
+ }
+
+ public static Response getCSARofSelectedResource(final AbstractComponentInstanceResource resource) {
+ final CSARExporter exporter = new CSARExporter();
+ StreamingOutput so = new StreamingOutput() {
+
+ @Override
+ public void write(OutputStream output) throws IOException, WebApplicationException {
+ try {
+ exporter.writeCSAR(resource.getId(), output);
+ } catch (Exception e) {
+ throw new WebApplicationException(e);
+ }
+ }
+ };
+ StringBuilder sb = new StringBuilder();
+ sb.append("attachment;filename=\"");
+ sb.append(resource.getXmlId().getEncoded());
+ sb.append(org.eclipse.winery.repository.Constants.SUFFIX_CSAR);
+ sb.append("\"");
+ return Response.ok().header("Content-Disposition", sb.toString()).type(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP).entity(so).build();
+ }
+
+ /**
+ * @return Singular type name for the given resource. E.g.,
+ * "ServiceTemplateResource" gets "ServiceTemplate"
+ */
+ public static String getTypeForInstance(Class<? extends AbstractComponentInstanceResource> resClass) {
+ String res = resClass.getName();
+ // Everything between the last "." and before "Resource" is the Type
+ int dotIndex = res.lastIndexOf('.');
+ assert (dotIndex >= 0);
+ return res.substring(dotIndex + 1, res.length() - "Resource".length());
+ }
+
+ /**
+ * @return Singular type name for the given id. E.g., "ServiceTemplateId"
+ * gets "ServiceTemplate"
+ */
+ public static String getTypeForAdminId(Class<? extends AdminId> idClass) {
+ return Util.getEverythingBetweenTheLastDotAndBeforeId(idClass);
+ }
+
+ /**
+ * @return Singular type name for given AbstractComponentsResource. E.g,
+ * "ServiceTemplatesResource" gets "ServiceTemplate"
+ */
+ public static String getTypeForComponentContainer(Class<? extends AbstractComponentsResource> containerClass) {
+ String res = containerClass.getName();
+ // Everything between the last "." and before "sResource" is the Type
+ int dotIndex = res.lastIndexOf('.');
+ assert (dotIndex >= 0);
+ return res.substring(dotIndex + 1, res.length() - "sResource".length());
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Class<? extends TOSCAComponentId> getComponentIdClass(String idClassName) {
+ String pkg = "org.eclipse.winery.common.ids.definitions.";
+ if (idClassName.contains("Import")) {
+ // quick hack to handle imports, which reside in their own package
+ pkg = pkg + "imports.";
+ }
+ String fullClassName = pkg + idClassName;
+ try {
+ return (Class<? extends TOSCAComponentId>) Class.forName(fullClassName);
+ } catch (ClassNotFoundException e) {
+ // quick hack for Ids local to winery repository
+ try {
+ fullClassName = "org.eclipse.winery.repository.datatypes.ids.admin." + idClassName;
+ return (Class<? extends TOSCAComponentId>) Class.forName(fullClassName);
+ } catch (ClassNotFoundException e2) {
+ String errorMsg = "Could not find id class for component container, " + fullClassName;
+ Utils.logger.error(errorMsg);
+ throw new IllegalStateException(errorMsg);
+ }
+ }
+ }
+
+ /**
+ * Returns a class object for ids of components nested in the given
+ * AbstractComponentsResource
+ */
+ public static Class<? extends TOSCAComponentId> getComponentIdClassForComponentContainer(Class<? extends AbstractComponentsResource> containerClass) {
+ // the name of the id class is the type + "Id"
+ String idClassName = Utils.getTypeForComponentContainer(containerClass) + "Id";
+
+ return Utils.getComponentIdClass(idClassName);
+ }
+
+ public static Class<? extends TOSCAComponentId> getComponentIdClassForTExtensibleElements(Class<? extends TExtensibleElements> clazz) {
+ // we assume that the clazzName always starts with a T.
+ // Therefore, we fetch everything after the last dot (plus offest 1)
+ String idClassName = clazz.getName();
+ int dotIndex = idClassName.lastIndexOf('.');
+ assert (dotIndex >= 0);
+ idClassName = idClassName.substring(dotIndex + 2) + "Id";
+
+ return Utils.getComponentIdClass(idClassName);
+ }
+
+
+ private static final String slashEncoded = Util.URLencode("/");
+
+
+ public static String getURLforPathInsideRepo(String pathInsideRepo) {
+ // first encode the whole string
+ String res = Util.URLencode(pathInsideRepo);
+ // issue: "/" is also encoded. This has to be undone:
+ res = res.replaceAll(Utils.slashEncoded, "/");
+ return res;
+ }
+
+
+ /**
+ * Shared object to map JSONs
+ */
+ public static final ObjectMapper mapper = new ObjectMapper();
+
+
+ public static String Object2JSON(Object o) {
+ String res;
+ try {
+ res = Utils.mapper.writeValueAsString(o);
+ } catch (Exception e) {
+ Utils.logger.error(e.getMessage(), e);
+ return null;
+ }
+ return res;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Class<? extends GenericId> getGenericIdClassForType(String typeIdType) {
+ Class<? extends GenericId> res;
+ // quick hack - we only need definitions right now
+ String pkg = "org.eclipse.winery.repository.datatypes.ids.definitions.";
+ String className = typeIdType;
+ className = pkg + className;
+ try {
+ res = (Class<? extends GenericId>) Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ Utils.logger.error("Could not find id class for id type", e);
+ res = null;
+ }
+ return res;
+ }
+
+ /**
+ * @return the absolute path for the given id
+ */
+ public static String getAbsoluteURL(GenericId id) {
+ return Prefs.INSTANCE.getResourcePath() + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id));
+ }
+
+ /**
+ * @param baseURI the URI from which the path should start
+ * @param id the generic id to resolve
+ *
+ * @return the relative path for the given id
+ */
+ public static String getRelativeURL(URI baseURI, GenericId id) {
+ String absolutePath = Prefs.INSTANCE.getResourcePath() + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id));
+ return baseURI.relativize(URI.create(absolutePath)).toString();
+ }
+
+ /**
+ * @return the absolute path for the given id
+ */
+ public static String getAbsoluteURL(RepositoryFileReference ref) {
+ return Prefs.INSTANCE.getResourcePath() + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref));
+ }
+
+ public static URI getAbsoluteURI(GenericId id) {
+ return Utils.createURI(Utils.getAbsoluteURL(id));
+ }
+
+ public static String doubleEscapeHTMLAndThenConvertNL2BR(String txt) {
+ String res = Functions.escapeXml(txt);
+ res = Functions.escapeXml(res);
+ res = res.replaceAll("\\n", "<br/>");
+ return res;
+ }
+
+ /**
+ * This method is similar to {@link
+ * org.eclipse.winery.common.Util.qname2href()}, but treats winery's
+ * internal ID model instead of the global TOSCA model
+ *
+ * @param id the id to create an <code>a href</code> element for
+ * @return an <code>a</code> HTML element pointing to the given id
+ */
+ public static String getHREF(TOSCAComponentId id) {
+ String res = "<a href=\"" + Utils.getAbsoluteURL(id) + "\">" + Functions.escapeXml(id.getXmlId().getDecoded()) + "</a>";
+ return res;
+ }
+
+ public static String artifactTypeQName2href(QName qname) {
+ return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TArtifactType.class, qname);
+ }
+
+ public static String nodeTypeQName2href(QName qname) {
+ return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TNodeType.class, qname);
+ }
+
+ public static String relationshipTypeQName2href(QName qname) {
+ return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TRelationshipType.class, qname);
+ }
+
+ public static String policyTypeQName2href(QName qname) {
+ return Util.qname2href(Prefs.INSTANCE.getResourcePath(), TPolicyType.class, qname);
+ }
+
+ /**
+ * Returns the middle part of the package name or the JSP location
+ *
+ * @param type the type
+ * @param separator the separator to be used, "." or "/"
+ * @return string which can be used "in the middle" of a package or of a
+ * path to a JSP
+ */
+ public static String getIntermediateLocationStringForType(String type, String separator) {
+ String location;
+ if (type.contains("ServiceTemplate")) {
+ location = "servicetemplates";
+ } else {
+ if (type.contains("TypeImplementation")) {
+ location = "entitytypeimplementations";
+ } else if (type.contains("Type")) {
+ location = "entitytypes";
+ } else if (type.contains("Import")) {
+ location = "imports";
+ } else {
+ assert (type.contains("Template"));
+ location = "entitytemplates";
+ }
+ // location now is the super pkg, we have to add a pkg of the type
+ location = location + separator + type.toLowerCase() + "s";
+ }
+ return location;
+ }
+
+ /**
+ * Required by topologyedit.jsp
+ *
+ * @return all known nodetype resources
+ */
+ public static Collection<NodeTypeResource> getAllNodeTypeResources() {
+ @SuppressWarnings("unchecked")
+ Collection<NodeTypeResource> res = (Collection<NodeTypeResource>) (Collection<?>) new NodeTypesResource().getAll();
+ return res;
+ }
+
+ /**
+ * Required by topologyedit.jsp
+ *
+ * @return all known relation ship type resources
+ */
+ public static Collection<RelationshipTypeResource> getAllRelationshipTypeResources() {
+ @SuppressWarnings("unchecked")
+ Collection<RelationshipTypeResource> res = (Collection<RelationshipTypeResource>) (Collection<?>) new RelationshipTypesResource().getAll();
+ return res;
+ }
+
+ /**
+ * @return the path to the Winery topology modeler. Required by
+ * functions.tld
+ */
+ public static String getWineryTopologyModelerPath() {
+ return Prefs.INSTANCE.getWineryTopologyModelerPath();
+ }
+
+ /**
+ * Detect the mime type of the stream. The stream is marked at the beginning
+ * and reset at the end
+ *
+ * @param is the stream
+ * @param fileName the fileName of the file belonging to the stream
+ */
+ public static String getMimeType(BufferedInputStream bis, String fn) throws IOException {
+ AutoDetectParser parser = new AutoDetectParser();
+ Detector detector = parser.getDetector();
+ Metadata md = new Metadata();
+ md.add(Metadata.RESOURCE_NAME_KEY, fn);
+ org.apache.tika.mime.MediaType mediaType = detector.detect(bis, md);
+ return mediaType.toString();
+ }
+
+
+ private static final MediaType MEDIATYPE_APPLICATION_OCTET_STREAM = MediaType.valueOf("application/octet-stream");
+
+
+ /**
+ * Fixes the mediaType if it is too vague (such as application/octet-stream)
+ *
+ * @return a more fitting MediaType or the original one if it is appropriate
+ * enough
+ */
+ public static MediaType getFixedMimeType(BufferedInputStream is, String fileName, MediaType mediaType) {
+ if (mediaType.equals(Utils.MEDIATYPE_APPLICATION_OCTET_STREAM)) {
+ // currently, we fix application/octet-stream only
+
+ // TODO: instead of using apache tika, we could hve a user-configured map storing
+ // * media type
+ // * file extension
+
+ try {
+ return MediaType.valueOf(Utils.getMimeType(is, fileName));
+ } catch (Exception e) {
+ Utils.logger.debug("Could not determine mimetype for " + fileName, e);
+ // just keep the old one
+ return mediaType;
+ }
+ } else {
+ return mediaType;
+ }
+ }
+
+ /**
+ * Converts the given object to XML.
+ *
+ * Used in cases the given element is not annotated with @XmlRoot
+ *
+ * We cannot use {@literal Class<? extends TExtensibleElements>} as, for
+ * instance, {@link TConstraint} does not inherit from
+ * {@link TExtensibleElements}
+ *
+ * @param clazz the Class of the passed object, required if obj is null
+ * @param obj the object to serialize
+ */
+ public static <T extends Object> Response getXML(Class<T> clazz, T obj) {
+ // see commit ab4b5c547619c058990 for an implementation using getJAXBElement,
+ // which can be directly passed as entity
+ // the issue is that we want to have a *formatted* XML
+ // Therefore, we serialize "by hand".
+ String xml = Utils.getXMLAsString(clazz, obj, false);
+
+ return Response.ok().type(MediaType.TEXT_XML).entity(xml).build();
+ }
+
+ public static <T extends Object> String getXMLAsString(Class<T> clazz, T obj, boolean includeProcessingInstruction) {
+ JAXBElement<T> rootElement = Util.getJAXBElement(clazz, obj);
+ Marshaller m = JAXBSupport.createMarshaller(includeProcessingInstruction);
+ StringWriter w = new StringWriter();
+ try {
+ m.marshal(rootElement, w);
+ } catch (JAXBException e) {
+ Utils.logger.error("Could not put content to string", e);
+ throw new IllegalStateException(e);
+ }
+ String res = w.toString();
+ return res;
+ }
+
+ public static String getXMLAsString(Object obj) {
+ if (obj instanceof Element) {
+ // in case the object is a DOM element, we use the DOM functionality
+ return Util.getXMLAsString((Element) obj);
+ } else {
+ return Utils.getXMLAsString(obj, false);
+ }
+ }
+
+ public static <T extends Object> String getXMLAsString(T obj, boolean includeProcessingInstruction) {
+ if (obj == null) {
+ return "";
+ }
+ @SuppressWarnings("unchecked")
+ Class<T> clazz = (Class<T>) obj.getClass();
+ return Utils.getXMLAsString(clazz, obj, includeProcessingInstruction);
+ }
+
+ public static String getAllXSDElementDefinitionsForTypeAheadSelection() {
+ Utils.logger.entry();
+ try {
+ return Utils.getAllXSDefinitionsForTypeAheadSelection(XSConstants.ELEMENT_DECLARATION);
+ } finally {
+ Utils.logger.exit();
+ }
+ }
+
+ public static String getAllXSDTypeDefinitionsForTypeAheadSelection() {
+ Utils.logger.entry();
+ try {
+ return Utils.getAllXSDefinitionsForTypeAheadSelection(XSConstants.TYPE_DEFINITION);
+ } finally {
+ Utils.logger.exit();
+ }
+ }
+
+ public static String getAllXSDefinitionsForTypeAheadSelection(short type) {
+ SortedSet<XSDImportId> allImports = Repository.INSTANCE.getAllTOSCAComponentIds(XSDImportId.class);
+
+ Map<Namespace, Collection<String>> data = new HashMap<Namespace, Collection<String>>();
+
+ for (XSDImportId id : allImports) {
+ XSDImportResource resource = new XSDImportResource(id);
+ Collection<String> allLocalNames = resource.getAllDefinedLocalNames(type);
+
+ Collection<String> list;
+ if ((list = data.get(id.getNamespace())) == null) {
+ // list does not yet exist
+ list = new ArrayList<String>();
+ data.put(id.getNamespace(), list);
+ }
+ assert (list != null);
+
+ list.addAll(allLocalNames);
+ }
+
+ ArrayNode rootNode = Utils.mapper.createArrayNode();
+
+ // ensure ordering in JSON object
+ Collection<Namespace> allns = new TreeSet<Namespace>();
+ allns.addAll(data.keySet());
+
+ for (Namespace ns : allns) {
+ Collection<String> localNames = data.get(ns);
+ if (!localNames.isEmpty()) {
+ ObjectNode groupEntry = Utils.mapper.createObjectNode();
+ rootNode.add(groupEntry);
+ groupEntry.put("text", ns.getDecoded());
+ ArrayNode children = Utils.mapper.createArrayNode();
+ groupEntry.put("children", children);
+ Collection<String> sortedLocalNames = new TreeSet<String>();
+ sortedLocalNames.addAll(localNames);
+ for (String localName : sortedLocalNames) {
+ String value = "{" + ns.getDecoded() + "}" + localName;
+ String text = localName;
+ ObjectNode o = Utils.mapper.createObjectNode();
+ o.put("text", text);
+ o.put("value", value);
+ children.add(o);
+ }
+ }
+ }
+
+ try {
+ return Utils.mapper.writeValueAsString(rootNode);
+ } catch (JsonProcessingException e) {
+ throw new IllegalStateException("Could not create JSON", e);
+ }
+ }
+
+ public static Response getResponseForException(Exception e) {
+ String msg;
+ if (e.getCause() != null) {
+ msg = e.getCause().getMessage();
+ } else {
+ msg = e.getMessage();
+ }
+ Response res = Response.status(Status.INTERNAL_SERVER_ERROR).entity(msg).build();
+ return res;
+ }
+
+ /**
+ * Returns the stored type for the given template
+ *
+ * Goes to the repository to retrieve stored data
+ *
+ * @param template the template to determine the type for
+ */
+ // we suppress "unchecked" as we use Class.forName
+ @SuppressWarnings("unchecked")
+ public static TEntityType getTypeForTemplate(TEntityTemplate template) {
+ QName type = template.getType();
+
+ // Possibilities:
+ // a) try all possibly types whether an appropriate QName exists
+ // b) derive type class from template class. Determine appropriate resource afterwards.
+ // We go for b)
+
+ String instanceResourceClassName = template.getClass().toString();
+ int idx = instanceResourceClassName.lastIndexOf('.');
+ // get everything from ".T", where "." is the last dot
+ instanceResourceClassName = instanceResourceClassName.substring(idx + 2);
+ // strip off "Template"
+ instanceResourceClassName = instanceResourceClassName.substring(0, instanceResourceClassName.length() - "Template".length());
+ // add "Type"
+ instanceResourceClassName += "Type";
+
+ // an id is required to instantiate the resource
+ String idClassName = "org.eclipse.winery.common.ids.definitions." + instanceResourceClassName + "Id";
+
+ String packageName = "org.eclipse.winery.repository.resources.entitytypes." + instanceResourceClassName.toLowerCase() + "s";
+ // convert from NodeType to NodeTypesResource
+ instanceResourceClassName += "Resource";
+ instanceResourceClassName = packageName + "." + instanceResourceClassName;
+
+ Utils.logger.debug("idClassName: {}", idClassName);
+ Utils.logger.debug("className: {}", instanceResourceClassName);
+
+ // Get instance of id class having "type" as id
+ Class<? extends TOSCAComponentId> idClass;
+ try {
+ idClass = (Class<? extends TOSCAComponentId>) Class.forName(idClassName);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Could not determine id class", e);
+ }
+ Constructor<? extends TOSCAComponentId> idConstructor;
+ try {
+ idConstructor = idClass.getConstructor(QName.class);
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException("Could not get QName id constructor", e);
+ }
+ TOSCAComponentId typeId;
+ try {
+ typeId = idConstructor.newInstance(type);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ throw new IllegalStateException("Could not instantiate type", e);
+ }
+
+ // now instantiate the resource, where the type belongs to
+ Class<? extends AbstractComponentInstanceResource> instanceResourceClass;
+ try {
+ instanceResourceClass = (Class<? extends AbstractComponentInstanceResource>) Class.forName(instanceResourceClassName);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Could not determine component instance resource class", e);
+ }
+ Constructor<? extends AbstractComponentInstanceResource> resConstructor;
+ try {
+ resConstructor = instanceResourceClass.getConstructor(typeId.getClass());
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new IllegalStateException("Could not get contructor", e);
+ }
+ AbstractComponentInstanceResource typeResource;
+ try {
+ typeResource = resConstructor.newInstance(typeId);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ throw new IllegalStateException("Could not instantiate resoruce", e);
+ }
+
+ // read the data from the resource and store it
+ TEntityType entityType = (TEntityType) typeResource.getElement();
+
+ return entityType;
+ }
+
+ /**
+ * referenced by functions.tld
+ */
+ public static Boolean isContainerLocallyAvailable() {
+ return Prefs.INSTANCE.isContainerLocallyAvailable();
+ }
+
+ /**
+ * referenced by functions.tld
+ *
+ * We need the bridge as functions (at tld) require a static method. We did
+ * not want to put two methods in Prefs and therefore, we put the method
+ * here.
+ */
+ public static Boolean isRestDocDocumentationAvailable() {
+ return Prefs.INSTANCE.isRestDocDocumentationAvailable();
+ }
+
+ public static boolean isSuccessFulResponse(Response res) {
+ return Status.fromStatusCode(res.getStatus()).getFamily().equals(Family.SUCCESSFUL);
+ }
+
+ /**
+ * Converts the given String to an integer. Fallback if String is a float.
+ * If String is an invalid number, "0" is returned
+ */
+ public static int convertStringToInt(String number) {
+ int intTop = 0;
+ try {
+ intTop = Integer.parseInt(number);
+ } catch (NumberFormatException e) {
+ try {
+ float floatTop = Float.parseFloat(number);
+ intTop = Math.round(floatTop);
+ } catch (NumberFormatException e2) {
+ // do nothing
+ }
+ }
+
+ return intTop;
+ }
+
+ /**
+ * Checks whether a given resource (with absolute URL!) is available with a
+ * HEAD request on it.
+ */
+ public static boolean isResourceAvailable(String path) {
+ Client client = Client.create();
+ WebResource wr = client.resource(path);
+ boolean res;
+ try {
+ ClientResponse response = wr.head();
+ res = (response.getClientResponseStatus().getFamily().equals(Family.SUCCESSFUL));
+ } catch (com.sun.jersey.api.client.ClientHandlerException ex) {
+ // In the case of a java.net.ConnectException, return false
+ res = false;
+ }
+ return res;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java
new file mode 100644
index 0000000..6417df6
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/AbstractRepository.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Date;
+
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.io.IOUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides basic implementations for {@link IRepository}
+ */
+public abstract class AbstractRepository implements IRepository {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractRepository.class);
+
+
+ /**
+ *
+ * @param ref the file reference to store the mime type for
+ * @return a reference to the file holding the mime type
+ */
+ private RepositoryFileReference getMimeFileRef(RepositoryFileReference ref) {
+ String fileName = ref.getFileName() + Constants.SUFFIX_MIMETYPE;
+ RepositoryFileReference mimeFileRef = new RepositoryFileReference(ref.getParent(), fileName);
+ return mimeFileRef;
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This is a simple implementation using the information put by
+ * setMimeType(RepositoryFileReference ref) or determining the mime type
+ * using Utils.getMimeType. If the latter is done, the mime type is
+ * persisted using setMimeType
+ */
+ @Override
+ public String getMimeType(RepositoryFileReference ref) throws IOException {
+ RepositoryFileReference mimeFileRef = this.getMimeFileRef(ref);
+ String mimeType;
+ if (this.exists(mimeFileRef)) {
+ InputStream is = this.newInputStream(mimeFileRef);
+ mimeType = IOUtils.toString(is, "UTF-8");
+ is.close();
+ } else {
+ // repository has been manipulated manually,
+ // create mimetype information
+ mimeType = null;
+ try (InputStream is = this.newInputStream(ref);
+ BufferedInputStream bis = new BufferedInputStream(is);) {
+ mimeType = Utils.getMimeType(bis, ref.getFileName());
+ }
+ if (mimeType != null) {
+ // successful execution
+ this.setMimeType(ref, MediaType.valueOf(mimeType));
+ } else {
+ AbstractRepository.logger.debug("Could not determine mimetype");
+ }
+ }
+ return mimeType;
+ }
+
+ /**
+ * Stores the mime type of the given file reference in a separate file
+ *
+ * This method calls putContentToFile(), where the filename is appended with
+ * Constants.SUFFIX_MIMETYPE and a null mime type. The latter indicates that
+ * no "normal" file is stored.
+ *
+ * @param ref the file reference
+ * @param mediaType the mimeType
+ */
+ protected void setMimeType(RepositoryFileReference ref, MediaType mediaType) throws IOException {
+ RepositoryFileReference mimeFileRef = this.getMimeFileRef(ref);
+ this.putContentToFile(mimeFileRef, mediaType.toString(), null);
+ }
+
+ @Override
+ public Date getConfigurationLastUpdate(GenericId id) {
+ RepositoryFileReference ref = BackendUtils.getRefOfConfiguration(id);
+ return this.getLastUpdate(ref);
+ }
+
+ @Override
+ public Configuration getConfiguration(GenericId id) {
+ RepositoryFileReference ref = BackendUtils.getRefOfConfiguration(id);
+ return this.getConfiguration(ref);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java
new file mode 100644
index 0000000..eeddfba
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/BackendUtils.java
@@ -0,0 +1,995 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.nio.file.attribute.FileTime;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.DateUtils;
+import org.apache.xerces.impl.dv.XSSimpleType;
+import org.apache.xerces.impl.xs.XSImplementationImpl;
+import org.apache.xerces.xs.XSComplexTypeDefinition;
+import org.apache.xerces.xs.XSElementDeclaration;
+import org.apache.xerces.xs.XSImplementation;
+import org.apache.xerces.xs.XSLoader;
+import org.apache.xerces.xs.XSModel;
+import org.apache.xerces.xs.XSModelGroup;
+import org.apache.xerces.xs.XSObjectList;
+import org.apache.xerces.xs.XSParticle;
+import org.apache.xerces.xs.XSTerm;
+import org.apache.xerces.xs.XSTypeDefinition;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.common.ids.IdUtil;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.definitions.EntityTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV;
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.tosca.Definitions;
+import org.eclipse.winery.model.tosca.ObjectFactory;
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.model.tosca.TDeploymentArtifacts;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TServiceTemplate;
+import org.eclipse.winery.model.tosca.TTopologyTemplate;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.JAXBSupport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.constants.Filename;
+import org.eclipse.winery.repository.datatypes.ids.admin.AdminId;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.IHasTypeReference;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources.admin.NamespacesResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource;
+import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportsResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.ls.LSInput;
+
+import com.sun.jersey.core.header.ContentDisposition;
+
+/**
+ * Contains generic utility functions for the Backend
+ *
+ * Contains everything that is useful for our ids etc. Does <em>not</em> contain
+ * anything that has to do with resources
+ */
+public class BackendUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(BackendUtils.class);
+
+
+ /**
+ * Deletes given file/dir and returns appropriate response code
+ */
+ public static Response delete(GenericId id) {
+ if (!Repository.INSTANCE.exists(id)) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ try {
+ Repository.INSTANCE.forceDelete(id);
+ } catch (IOException e) {
+ BackendUtils.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ return Response.noContent().build();
+ }
+
+ /**
+ * Deletes given file and returns appropriate response code
+ */
+ public static Response delete(RepositoryFileReference ref) {
+ if (!Repository.INSTANCE.exists(ref)) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ try {
+ Repository.INSTANCE.forceDelete(ref);
+ } catch (IOException e) {
+ BackendUtils.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ return Response.ok().build();
+ }
+
+ /**
+ * Generates given TOSCA element and returns appropriate response code <br />
+ *
+ * In the case of an existing resource, the other possible return code is
+ * 302. This code has no Status constant, therefore we use Status.CONFLICT,
+ * which is also possible.
+ *
+ * @return <ul>
+ * <li>
+ * <ul>
+ * <li>Status.CREATED (201) if the resource has been created,</li>
+ * <li>Status.CONFLICT if the resource already exists,</li>
+ * <li>Status.INTERNAL_SERVER_ERROR (500) if something went wrong</li>
+ * </ul>
+ * </li>
+ * <li>URI: the absolute URI of the newly created resource</li>
+ * </ul>
+ */
+ public static ResourceCreationResult create(GenericId id) {
+ ResourceCreationResult res = new ResourceCreationResult();
+ if (Repository.INSTANCE.exists(id)) {
+ // res.setStatus(302);
+ res.setStatus(Status.CONFLICT);
+ } else {
+ if (Repository.INSTANCE.flagAsExisting(id)) {
+ res.setStatus(Status.CREATED);
+ // @formatter:off
+ // This method is a generic method
+ // We cannot return an "absolute" URL as the URL is always
+ // relative to the caller
+ // Does not work: String path = Prefs.INSTANCE.getResourcePath()
+ // + "/" +
+ // Utils.getURLforPathInsideRepo(id.getPathInsideRepo());
+ // We distinguish between two cases: TOSCAcomponentId and
+ // TOSCAelementId
+ // @formatter:on
+ String path;
+ if (id instanceof TOSCAComponentId) {
+ // here, we return namespace + id, as it is only possible to
+ // post on the TOSCA component*s* resource to create an
+ // instance of a TOSCA component
+ TOSCAComponentId tcId = (TOSCAComponentId) id;
+ path = tcId.getNamespace().getEncoded() + "/" + tcId.getXmlId().getEncoded() + "/";
+ } else {
+ assert (id instanceof TOSCAElementId);
+ // We just return the id as we assume that only the parent
+ // of this id may create sub elements
+ path = id.getXmlId().getEncoded() + "/";
+ }
+ // we have to encode it twice to get correct URIs
+ path = Utils.getURLforPathInsideRepo(path);
+ URI uri = Utils.createURI(path);
+ res.setUri(uri);
+ res.setId(id);
+ } else {
+ res.setStatus(Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+ return res;
+ }
+
+ /**
+ *
+ * Sends the file if modified and "not modified" if not modified future work
+ * may put each file with a unique id in a separate folder in tomcat * use
+ * that static URL for each file * if file is modified, URL of file changes
+ * * -> client always fetches correct file
+ *
+ * additionally "Vary: Accept" header is added (enables caching of the
+ * response)
+ *
+ * method header for calling method public <br />
+ * <code>Response getXY(@HeaderParam("If-Modified-Since") String modified) {...}</code>
+ *
+ *
+ * @param ref references the file to be send
+ * @param modified - HeaderField "If-Modified-Since" - may be "null"
+ * @return Response to be sent to the client
+ */
+ public static Response returnRepoPath(RepositoryFileReference ref, String modified) {
+ return BackendUtils.returnRefAsResponseBuilder(ref, modified).build();
+ }
+
+ /**
+ * @return true if given fileDate is newer then the modified date (or
+ * modified is null)
+ */
+ public static boolean isFileNewerThanModifiedDate(long millis, String modified) {
+ if (modified == null) {
+ return true;
+ }
+
+ Date modifiedDate = null;
+
+ assert (Locale.getDefault() == Locale.ENGLISH);
+ try {
+ modifiedDate = DateUtils.parseDate(modified, org.apache.http.impl.cookie.DateUtils.DEFAULT_PATTERNS);
+ } catch (ParseException e) {
+ BackendUtils.logger.error(e.getMessage(), e);
+ }
+
+ if (modifiedDate != null) {
+ // modifiedDate does not carry milliseconds, but fileDate does
+ // therefore we have to do a range-based comparison
+ if ((millis - modifiedDate.getTime()) < DateUtils.MILLIS_PER_SECOND) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * This is not repository specific, but we leave it close to the only caller
+ *
+ * If the passed ref is newer than the modified date (or the modified date
+ * is null), an OK response with an inputstream pointing to the path is
+ * returned
+ */
+ private static ResponseBuilder returnRefAsResponseBuilder(RepositoryFileReference ref, String modified) {
+ if (!Repository.INSTANCE.exists(ref)) {
+ return Response.status(Status.NOT_FOUND);
+ }
+
+ FileTime lastModified;
+ try {
+ lastModified = Repository.INSTANCE.getLastModifiedTime(ref);
+ } catch (IOException e1) {
+ BackendUtils.logger.debug("Could not get lastModifiedTime", e1);
+ return Response.serverError();
+ }
+
+ // do we really need to send the file or can send "not modified"?
+ if (!BackendUtils.isFileNewerThanModifiedDate(lastModified.toMillis(), modified)) {
+ return Response.status(Status.NOT_MODIFIED);
+ }
+
+ ResponseBuilder res;
+ try {
+ res = Response.ok(Repository.INSTANCE.newInputStream(ref));
+ } catch (IOException e) {
+ BackendUtils.logger.debug("Could not open input stream", e);
+ return Response.serverError();
+ }
+ res = res.lastModified(new Date(lastModified.toMillis()));
+ // vary:accept header is always set to be safe
+ res = res.header(HttpHeaders.VARY, HttpHeaders.ACCEPT);
+ // determine and set MIME content type
+ try {
+ res = res.header(HttpHeaders.CONTENT_TYPE, Repository.INSTANCE.getMimeType(ref));
+ } catch (IOException e) {
+ BackendUtils.logger.debug("Could not determine mime type", e);
+ return Response.serverError();
+ }
+ // set filename
+ ContentDisposition contentDisposition = ContentDisposition.type("attachment").fileName(ref.getFileName()).modificationDate(new Date(lastModified.toMillis())).build();
+ res.header("Content-Disposition", contentDisposition);
+ return res;
+ }
+
+ /**
+ * Updates the given property in the given configuration. Currently always
+ * returns "no content", because the underlying class does not report any
+ * errors during updating. <br />
+ *
+ * If null or "" is passed as value, the property is cleared
+ *
+ * @return Status.NO_CONTENT
+ */
+ public static Response updateProperty(Configuration configuration, String property, String val) {
+ if (StringUtils.isBlank(val)) {
+ configuration.clearProperty(property);
+ } else {
+ configuration.setProperty(property, val);
+ }
+ return Response.noContent().build();
+ }
+
+ /**
+ * Persists the resource and returns appropriate response
+ */
+ public static Response persist(IPersistable res) {
+ Response r;
+ try {
+ res.persist();
+ } catch (IOException e) {
+ BackendUtils.logger.debug("Could not persist resource", e);
+ r = Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build();
+ return r;
+ }
+ r = Response.noContent().build();
+ return r;
+ }
+
+ /**
+ * Writes data to file. Replaces the file's content with the given content.
+ * The file does not need to exist
+ *
+ * @param ref Reference to the File to write to (overwrite)
+ * @param content the data to write
+ * @return a JAX-RS Response containing the result. NOCONTENT if successful,
+ * InternalSeverError otherwise
+ */
+ public static Response putContentToFile(RepositoryFileReference ref, String content, MediaType mediaType) {
+ try {
+ Repository.INSTANCE.putContentToFile(ref, content, mediaType);
+ } catch (IOException e) {
+ BackendUtils.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ return Response.noContent().build();
+ }
+
+ public static Response putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) {
+ try {
+ Repository.INSTANCE.putContentToFile(ref, inputStream, mediaType);
+ } catch (IOException e) {
+ BackendUtils.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ return Response.noContent().build();
+ }
+
+ public static <T extends TOSCAComponentId> T getTOSCAcomponentId(Class<T> idClass, String qnameStr) {
+ QName qname = QName.valueOf(qnameStr);
+ return BackendUtils.getTOSCAcomponentId(idClass, qname.getNamespaceURI(), qname.getLocalPart(), false);
+ }
+
+ public static <T extends TOSCAComponentId> T getTOSCAcomponentId(Class<T> idClass, QName qname) {
+ // we got two implementation possibilities: one is to directly use the
+ // QName constructor,
+ // the other is to use a namespace, localname, urlencoded constructor
+ // we opt for the latter one, which forces the latter constructor to
+ // exist at all ids
+ return BackendUtils.getTOSCAcomponentId(idClass, qname.getNamespaceURI(), qname.getLocalPart(), false);
+ }
+
+ public static <T extends TOSCAComponentId> T getTOSCAcomponentId(Class<T> idClass, String namespace, String id, boolean URLencoded) {
+ Constructor<T> constructor;
+ try {
+ constructor = idClass.getConstructor(String.class, String.class, boolean.class);
+ } catch (NoSuchMethodException | SecurityException e) {
+ BackendUtils.logger.error("Could not get constructor for id " + idClass.getName(), e);
+ throw new IllegalStateException(e);
+ }
+ T tcId;
+ try {
+ tcId = constructor.newInstance(namespace, id, URLencoded);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ BackendUtils.logger.error("Could not create id instance", e);
+ throw new IllegalStateException(e);
+ }
+ return tcId;
+ }
+
+ /**
+ * @param id the id to determine the namespace of the parent for
+ * @return the namespace of the first TOSCAcomponentId found in the ID
+ * hierarchy
+ */
+ public static Namespace getNamespace(TOSCAElementId id) {
+ GenericId parent = id.getParent();
+ while (!(parent instanceof TOSCAComponentId)) {
+ parent = parent.getParent();
+ }
+ return ((TOSCAComponentId) parent).getNamespace();
+ }
+
+ public static String getName(TOSCAComponentId instanceId) {
+ // TODO: Here is a performance issue as we don't use caching or a database
+ // Bad, but without performance loss: Use "text = instanceId.getXmlId().getDecoded();"
+ TExtensibleElements instanceElement = AbstractComponentsResource.getComponentInstaceResource(instanceId).getElement();
+ return ModelUtilities.getNameWithIdFallBack(instanceElement);
+ }
+
+/**
+ * Do <em>not</em> use this for creating URLs. Use
+ *
+ * {@link org.eclipse.winery.repository.Utils.getURLforPathInsideRepo(String)}
+ *
+ * or
+ *
+ * {@link org.eclipse.winery.repository.Utils.getAbsoluteURL(GenericId)
+ * instead.
+ *
+ * @return the path starting from the root element to the current element.
+ * Separated by "/", URLencoded, but <b>not</b> double encoded. With
+ * trailing slash if sub-resources can exist
+ * @throws IllegalStateException if id is of an unknown subclass of id
+ */
+ public static String getPathInsideRepo(GenericId id) {
+ if (id == null) {
+ throw new NullPointerException("id is null");
+ }
+
+ // for creating paths see also org.eclipse.winery.repository.Utils.getIntermediateLocationStringForType(String, String)
+ // and org.eclipse.winery.common.Util.getRootPathFragment(Class<? extends TOSCAcomponentId>)
+ if (id instanceof AdminId) {
+ return "admin/" + id.getXmlId().getEncoded() + "/";
+ } else if (id instanceof GenericImportId) {
+ GenericImportId i = (GenericImportId) id;
+ String res = "imports/";
+ res = res + Util.URLencode(i.getType()) + "/";
+ res = res + i.getNamespace().getEncoded() + "/";
+ res = res + i.getXmlId().getEncoded() + "/";
+ return res;
+ } else if (id instanceof TOSCAComponentId) {
+ return IdUtil.getPathFragment(id);
+ } else if (id instanceof TOSCAElementId) {
+ // we cannot reuse IdUtil.getPathFragment(id) as this TOSCAelementId
+ // might be nested in an AdminId
+ return BackendUtils.getPathInsideRepo(id.getParent()) + id.getXmlId().getEncoded() + "/";
+ } else {
+ throw new IllegalStateException("Unknown subclass of GenericId " + id.getClass());
+ }
+ }
+
+/**
+ * Do <em>not</em> use this for creating URLs. Use
+ *
+ * {@link org.eclipse.winery.repository.Utils.getURLforPathInsideRepo(String)}
+ *
+ * or
+ *
+ * {@link org.eclipse.winery.repository.Utils.getAbsoluteURL(GenericId)
+ * instead.
+ *
+ * @return the path starting from the root element to the current element.
+ * Separated by "/", parent URLencoded. Without trailing slash.
+ */
+ public static String getPathInsideRepo(RepositoryFileReference ref) {
+ return BackendUtils.getPathInsideRepo(ref.getParent()) + ref.getFileName();
+ }
+
+ /**
+ * Returns the reference to the definitions XML storing the TOSCA for the
+ * given id
+ *
+ * @param id the id to lookup
+ * @return the reference
+ */
+ public static RepositoryFileReference getRefOfDefinitions(TOSCAComponentId id) {
+ String name = Util.getTypeForComponentId(id.getClass());
+ name = name + Constants.SUFFIX_TOSCA_DEFINITIONS;
+ RepositoryFileReference ref = new RepositoryFileReference(id, name);
+ return ref;
+ }
+
+ /**
+ * Returns the reference to the properties file storing the TOSCA
+ * information for the given id
+ *
+ * @param id the id to lookup
+ * @return the reference
+ */
+ public static RepositoryFileReference getRefOfConfiguration(GenericId id) {
+ String name;
+ // Hack to determine file name
+ if (id instanceof TOSCAComponentId) {
+ name = Util.getTypeForComponentId(((TOSCAComponentId) id).getClass());
+ name = name + Constants.SUFFIX_PROPERTIES;
+ } else if (id instanceof AdminId) {
+ name = Utils.getTypeForAdminId(((AdminId) id).getClass());
+ name = name + Constants.SUFFIX_PROPERTIES;
+ } else {
+ assert (id instanceof TOSCAElementId);
+ TOSCAElementId tId = (TOSCAElementId) id;
+ if (tId instanceof PlansId) {
+ name = Filename.FILENAME_PROPERTIES_PLANCONTAINER;
+ } else if (tId instanceof VisualAppearanceId) {
+ // quick hack for special name here
+ name = Filename.FILENAME_PROPERTIES_VISUALAPPEARANCE;
+ } else {
+ name = Util.getTypeForElementId(tId.getClass()) + Constants.SUFFIX_PROPERTIES;
+ }
+ }
+
+ RepositoryFileReference ref = new RepositoryFileReference(id, name);
+ return ref;
+ }
+
+ /**
+ * @param qNameOfTheType the QName of the type, where all TOSCAComponentIds,
+ * where the associated element points to the type
+ * @param clazz the Id class of the entities to discover
+ */
+ public static <X extends TOSCAComponentId> Collection<X> getAllElementsRelatedWithATypeAttribute(Class<X> clazz, QName qNameOfTheType) {
+ // we do not use any database system,
+ // therefore we have to crawl through each node type implementation by ourselves
+ SortedSet<X> allIds = Repository.INSTANCE.getAllTOSCAComponentIds(clazz);
+ Collection<X> res = new HashSet<>();
+ for (X id : allIds) {
+ IHasTypeReference resource;
+ try {
+ resource = (IHasTypeReference) AbstractComponentsResource.getComponentInstaceResource(id);
+ } catch (ClassCastException e) {
+ String error = "Requested following the type, but the component instance does not implmenet IHasTypeReference";
+ BackendUtils.logger.error(error);
+ throw new IllegalStateException(error);
+ }
+ // The resource may have been freshly initialized due to existence of a directory
+ // then it has no node type assigned leading to ntiRes.getType() being null
+ // we ignore this error here
+ if (qNameOfTheType.equals(resource.getType())) {
+ // the component instance is an implementation of the associated node type
+ res.add(id);
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Returns a list of the topology template nested in the given service
+ * template
+ */
+ public static List<TNodeTemplate> getAllNestedNodeTemplates(TServiceTemplate serviceTemplate) {
+ List<TNodeTemplate> l = new ArrayList<TNodeTemplate>();
+ TTopologyTemplate topologyTemplate = serviceTemplate.getTopologyTemplate();
+ if (topologyTemplate == null) {
+ return Collections.emptyList();
+ }
+ for (TEntityTemplate t : topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
+ if (t instanceof TNodeTemplate) {
+ l.add((TNodeTemplate) t);
+ }
+ }
+ return l;
+ }
+
+ private static Collection<QName> getAllReferencedArtifactTemplates(TDeploymentArtifacts tDeploymentArtifacts) {
+ if (tDeploymentArtifacts == null) {
+ return Collections.emptyList();
+ }
+ List<TDeploymentArtifact> deploymentArtifacts = tDeploymentArtifacts.getDeploymentArtifact();
+ if (deploymentArtifacts == null) {
+ return Collections.emptyList();
+ }
+ Collection<QName> res = new ArrayList<>();
+ for (TDeploymentArtifact da : deploymentArtifacts) {
+ QName artifactRef = da.getArtifactRef();
+ if (artifactRef != null) {
+ res.add(artifactRef);
+ }
+ }
+ return res;
+ }
+
+ private static Collection<QName> getAllReferencedArtifactTemplates(TImplementationArtifacts tImplementationArtifacts) {
+ if (tImplementationArtifacts == null) {
+ return Collections.emptyList();
+ }
+ List<ImplementationArtifact> implementationArtifacts = tImplementationArtifacts.getImplementationArtifact();
+ if (implementationArtifacts == null) {
+ return Collections.emptyList();
+ }
+ Collection<QName> res = new ArrayList<>();
+ for (ImplementationArtifact ia : implementationArtifacts) {
+ QName artifactRef = ia.getArtifactRef();
+ if (artifactRef != null) {
+ res.add(artifactRef);
+ }
+ }
+ return res;
+ }
+
+ public static Collection<QName> getArtifactTemplatesOfReferencedDeploymentArtifacts(TNodeTemplate nodeTemplate) {
+ List<QName> l = new ArrayList<QName>();
+
+ // DAs may be assigned directly to a node template
+ Collection<QName> allReferencedArtifactTemplates = BackendUtils.getAllReferencedArtifactTemplates(nodeTemplate.getDeploymentArtifacts());
+ l.addAll(allReferencedArtifactTemplates);
+
+ // DAs may be assigned via node type implementations
+ QName nodeTypeQName = nodeTemplate.getType();
+ Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, nodeTypeQName);
+ for (NodeTypeImplementationId nodeTypeImplementationId : allNodeTypeImplementations) {
+ NodeTypeImplementationResource ntiRes = new NodeTypeImplementationResource(nodeTypeImplementationId);
+ allReferencedArtifactTemplates = BackendUtils.getAllReferencedArtifactTemplates(ntiRes.getNTI().getDeploymentArtifacts());
+ l.addAll(allReferencedArtifactTemplates);
+ }
+
+ return l;
+ }
+
+ public static Collection<QName> getArtifactTemplatesOfReferencedImplementationArtifacts(TNodeTemplate nodeTemplate) {
+ List<QName> l = new ArrayList<QName>();
+
+ // IAs may be assigned via node type implementations
+ QName nodeTypeQName = nodeTemplate.getType();
+ Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, nodeTypeQName);
+ for (NodeTypeImplementationId nodeTypeImplementationId : allNodeTypeImplementations) {
+ NodeTypeImplementationResource ntiRes = new NodeTypeImplementationResource(nodeTypeImplementationId);
+ Collection<QName> allReferencedArtifactTemplates = BackendUtils.getAllReferencedArtifactTemplates(ntiRes.getNTI().getImplementationArtifacts());
+ l.addAll(allReferencedArtifactTemplates);
+ }
+
+ return l;
+ }
+
+ /**
+ * Creates a new TDefintions element wrapping a TOSCA Component instance.
+ * The namespace of the tosca component is used as namespace and
+ * {@code winery-defs-for-} concatenated with the (unique) ns prefix and
+ * idOfContainedElement is used as id
+ *
+ * @param toscAcomponentId the id of the element the wrapper is used for
+ *
+ * @return a definitions element prepared for wrapping a TOSCA component
+ * instance
+ */
+ public static Definitions createWrapperDefinitions(TOSCAComponentId tcId) {
+ ObjectFactory of = new ObjectFactory();
+ Definitions defs = of.createDefinitions();
+
+ // set target namespace
+ // an internal namespace is not possible
+ // a) tPolicyTemplate and tArtfactTemplate do NOT support the "targetNamespace" attribute
+ // b) the imports statement would look bad as it always imported the artificial namespace
+ defs.setTargetNamespace(tcId.getNamespace().getDecoded());
+
+ // set a unique id to create a valid definitions element
+ // we do not use UUID to be more human readable and deterministic (for debugging)
+ String prefix = NamespacesResource.getPrefix(tcId.getNamespace());
+ String elId = tcId.getXmlId().getDecoded();
+ String id = "winery-defs-for_" + prefix + "-" + elId;
+ defs.setId(id);
+
+ return defs;
+ }
+
+ /**
+ * @throws IOException if content could not be updated in the repository
+ * @throws IllegalStateException if an JAXBException occurred. This should
+ * never happen.
+ */
+ public static void persist(Object o, RepositoryFileReference ref, MediaType mediaType) throws IOException {
+ // We assume that the object is not too large
+ // Otherwise, http://io-tools.googlecode.com/svn/www/easystream/apidocs/index.html should be used
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Marshaller m;
+ try {
+ m = JAXBSupport.createMarshaller(true);
+ m.marshal(o, out);
+ } catch (JAXBException e) {
+ BackendUtils.logger.error("Could not put content to file", e);
+ throw new IllegalStateException(e);
+ }
+ byte[] data = out.toByteArray();
+ ByteArrayInputStream in = new ByteArrayInputStream(data);
+ // this may throw an IOExcpetion. We propagate this exception.
+ Repository.INSTANCE.putContentToFile(ref, in, mediaType);
+ }
+
+ /**
+ * Updates the color if the color is not yet existent
+ *
+ * @param name the name of the component. Used as basis for a generated
+ * color
+ * @param qname the QName of the color attribute
+ * @param otherAttributes the plain "XML" attributes. They are used to check
+ * @param res
+ */
+ public static String getColorAndSetDefaultIfNotExisting(String name, QName qname, Map<QName, String> otherAttributes, TopologyGraphElementEntityTypeResource res) {
+ String colorStr = otherAttributes.get(qname);
+ if (colorStr == null) {
+ colorStr = Util.getColor(name);
+ otherAttributes.put(qname, colorStr);
+ BackendUtils.persist(res);
+ }
+ return colorStr;
+ }
+
+ /**
+ *
+ * @param tcId The element type id to get the location for
+ * @param uri uri to use if in XML export mode, null if in CSAR export mode
+ * @param wrapperElementLocalName the local name of the wrapper element
+ * @return
+ */
+ public static String getImportLocationForWinerysPropertiesDefinitionXSD(EntityTypeId tcId, URI uri, String wrapperElementLocalName) {
+ String loc = BackendUtils.getPathInsideRepo(tcId);
+ loc = loc + "propertiesdefinition/";
+ loc = Utils.getURLforPathInsideRepo(loc);
+ if (uri == null) {
+ loc = loc + wrapperElementLocalName + ".xsd";
+ // for the import later, we need "../" in front
+ loc = "../" + loc;
+ } else {
+ loc = uri + loc + "xsd";
+ }
+ return loc;
+ }
+
+ /**
+ * @param ref the file to read from
+ */
+ public static XSModel getXSModel(final RepositoryFileReference ref) {
+ if (ref == null) {
+ return null;
+ }
+ final InputStream is;
+ try {
+ is = Repository.INSTANCE.newInputStream(ref);
+ } catch (IOException e) {
+ BackendUtils.logger.debug("Could not create input stream", e);
+ return null;
+ }
+
+ // we rely on xerces to parse the XSD
+ // idea based on http://stackoverflow.com/a/5165177/873282
+ XSImplementation impl = new XSImplementationImpl();
+ XSLoader schemaLoader = impl.createXSLoader(null);
+
+ // minimal LSInput implementation sufficient for XSLoader in Oracle's JRE7
+ LSInput input = new LSInput() {
+
+ @Override
+ public void setSystemId(String systemId) {
+ }
+
+ @Override
+ public void setStringData(String stringData) {
+ }
+
+ @Override
+ public void setPublicId(String publicId) {
+ }
+
+ @Override
+ public void setEncoding(String encoding) {
+ }
+
+ @Override
+ public void setCharacterStream(Reader characterStream) {
+ }
+
+ @Override
+ public void setCertifiedText(boolean certifiedText) {
+ }
+
+ @Override
+ public void setByteStream(InputStream byteStream) {
+ }
+
+ @Override
+ public void setBaseURI(String baseURI) {
+ }
+
+ @Override
+ public String getSystemId() {
+ return null;
+ }
+
+ @Override
+ public String getStringData() {
+ return null;
+ }
+
+ @Override
+ public String getPublicId() {
+ return BackendUtils.getPathInsideRepo(ref);
+ }
+
+ @Override
+ public String getEncoding() {
+ return "UTF-8";
+ }
+
+ @Override
+ public Reader getCharacterStream() {
+ try {
+ return new InputStreamReader(is, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ System.out.println("exeption");
+ throw new IllegalStateException("UTF-8 is unkown", e);
+ }
+ }
+
+ @Override
+ public boolean getCertifiedText() {
+ return false;
+ }
+
+ @Override
+ public InputStream getByteStream() {
+ return null;
+ }
+
+ @Override
+ public String getBaseURI() {
+ return null;
+ }
+ };
+ XSModel model = schemaLoader.load(input);
+ return model;
+ }
+
+ /**
+ * Derives Winery's Properties Definition from an existing properties
+ * definition
+ *
+ * @param ci the entity type to try to modify the WPDs
+ * @param errors the list to add errors to
+ */
+ public static void deriveWPD(TEntityType ci, List<String> errors) {
+ BackendUtils.logger.trace("deriveWPD");
+ PropertiesDefinition propertiesDefinition = ci.getPropertiesDefinition();
+ QName element = propertiesDefinition.getElement();
+ if (element == null) {
+ BackendUtils.logger.debug("only works for an element definition, not for types");
+ } else {
+ BackendUtils.logger.debug("Looking for the definition of {" + element.getNamespaceURI() + "}" + element.getLocalPart());
+ // fetch the XSD defining the element
+ XSDImportsResource importsRes = new XSDImportsResource();
+ Map<String, RepositoryFileReference> mapFromLocalNameToXSD = importsRes.getMapFromLocalNameToXSD(element.getNamespaceURI(), false);
+ RepositoryFileReference ref = mapFromLocalNameToXSD.get(element.getLocalPart());
+ if (ref == null) {
+ String msg = "XSD not found for " + element.getNamespaceURI() + " / " + element.getLocalPart();
+ BackendUtils.logger.debug(msg);
+ errors.add(msg);
+ return;
+ }
+
+ XSModel xsModel = BackendUtils.getXSModel(ref);
+ XSElementDeclaration elementDeclaration = xsModel.getElementDeclaration(element.getLocalPart(), element.getNamespaceURI());
+ if (elementDeclaration == null) {
+ String msg = "XSD model claimed to contain declaration for {" + element.getNamespaceURI() + "}" + element.getLocalPart() + ", but it did not.";
+ BackendUtils.logger.debug(msg);
+ errors.add(msg);
+ return;
+ }
+
+ // go through the XSD definition and
+ XSTypeDefinition typeDefinition = elementDeclaration.getTypeDefinition();
+ if (typeDefinition instanceof XSComplexTypeDefinition) {
+ XSComplexTypeDefinition cTypeDefinition = (XSComplexTypeDefinition) typeDefinition;
+ XSParticle particle = cTypeDefinition.getParticle();
+ if (particle == null) {
+ BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Complex type does not contain particles");
+ } else {
+ XSTerm term = particle.getTerm();
+ if (term instanceof XSModelGroup) {
+ XSModelGroup modelGroup = (XSModelGroup) term;
+ if (modelGroup.getCompositor() == XSModelGroup.COMPOSITOR_SEQUENCE) {
+ XSObjectList particles = modelGroup.getParticles();
+ int len = particles.getLength();
+ boolean everyThingIsASimpleType = true;
+ PropertyDefinitionKVList list = new PropertyDefinitionKVList();
+ if (len != 0) {
+ for (int i = 0; i < len; i++) {
+ XSParticle innerParticle = (XSParticle) particles.item(i);
+ XSTerm innerTerm = innerParticle.getTerm();
+ if (innerTerm instanceof XSElementDeclaration) {
+ XSElementDeclaration innerElementDeclaration = (XSElementDeclaration) innerTerm;
+ String name = innerElementDeclaration.getName();
+ XSTypeDefinition innerTypeDefinition = innerElementDeclaration.getTypeDefinition();
+ if (innerTypeDefinition instanceof XSSimpleType) {
+ XSSimpleType xsSimpleType = (XSSimpleType) innerTypeDefinition;
+ String typeNS = xsSimpleType.getNamespace();
+ String typeName = xsSimpleType.getName();
+ if (typeNS.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
+ PropertyDefinitionKV def = new PropertyDefinitionKV();
+ def.setKey(name);
+ // convention at WPD: use "xsd" as prefix for XML Schema Definition
+ def.setType("xsd:" + typeName);
+ list.add(def);
+ } else {
+ everyThingIsASimpleType = false;
+ break;
+ }
+ } else {
+ everyThingIsASimpleType = false;
+ break;
+ }
+ } else {
+ everyThingIsASimpleType = false;
+ break;
+ }
+ }
+ }
+ if (everyThingIsASimpleType) {
+ // everything went allright, we can add a WPD
+ WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition();
+ wpd.setIsDerivedFromXSD(Boolean.TRUE);
+ wpd.setElementName(element.getLocalPart());
+ wpd.setNamespace(element.getNamespaceURI());
+ wpd.setPropertyDefinitionKVList(list);
+ ModelUtilities.replaceWinerysPropertiesDefinition(ci, wpd);
+ BackendUtils.logger.debug("Successfully generated WPD");
+ } else {
+ BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Not all types in the sequence are simple types");
+ }
+ } else {
+ BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Model group is not a sequence");
+ }
+ } else {
+ BackendUtils.logger.debug("XSD does not follow the requirements put by winery: Not a model group");
+ }
+ }
+ } else {
+ BackendUtils.logger.debug("XSD does not follow the requirements put by winery: No Complex Type Definition");
+ }
+ }
+ }
+
+ /**
+ * Returns all components available of the given id type
+ *
+ * Similar functionality as {@link
+ * org.eclipse.winery.repository.backend.IGenericRepository.
+ * getAllTOSCAComponentIds(Class<T>)}, but it crawls through the repository
+ *
+ * This method is required as we do not use a database.
+ *
+ * @param idClass class of the Ids to search for
+ * @return empty set if no ids are available
+ */
+ public <T extends TOSCAElementId> SortedSet<T> getAllTOSCAElementIds(Class<T> idClass) {
+ throw new IllegalStateException("Not yet implemented");
+
+ /*
+ Implementation idea:
+ * switch of instance of idClass
+ * nodetemplate / relationshiptemplate -> fetch all service templates -> crawl through topology -> add all to res
+ * req/cap do as above, but inspect nodetemplate
+ * (other special handlings; check spec where each type can be linked from)
+ */
+ }
+
+ /**
+ * Converts the given collection of TOSCA Component Ids to a collection of
+ * QNames by using the getQName() method.
+ *
+ * This is required for QNameChooser.tag
+ */
+ public static Collection<QName> convertTOSCAComponentIdCollectionToQNameCollection(Collection<? extends TOSCAComponentId> col) {
+ Collection<QName> res = new ArrayList<>();
+ for (TOSCAComponentId id : col) {
+ res.add(id.getQName());
+ }
+ return res;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java
new file mode 100644
index 0000000..9e7ba66
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IGenericRepository.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.attribute.FileTime;
+import java.util.Collection;
+import java.util.Date;
+import java.util.SortedSet;
+
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+import org.eclipse.winery.common.interfaces.IWineryRepositoryCommon;
+
+/**
+ * Enables access to the winery repository via Ids defined in package
+ * {@link org.eclipse.winery.common.ids}
+ *
+ * In contrast to {@link org.eclipse.winery.repository.backend.IRepository},
+ * this is NOT dependent on a particular storage format for the properties.
+ * These two classes exist to make the need for reengineering explicit.
+ *
+ * This is a first attempt to offer methods via GenericId. It might happen, that
+ * methods, where GenericIds make sense, are simply added to "IWineryRepository"
+ * instead of being added here.
+ *
+ * The ultimate goal is to get rid of this class and to have
+ * IWineryRepositoryCommon only.
+ *
+ * Currently, this class is used internally only
+ */
+interface IGenericRepository extends IWineryRepositoryCommon {
+
+ /**
+ * Flags the given TOSCA element as existing. The resources itself create
+ * appropriate data files.
+ *
+ * Pre-Condition: !exists(id)<br/>
+ * Post-Condition: exists(id)
+ *
+ * Typically, the given TOSCA element is created if a configuration is asked
+ * for
+ *
+ * @param id
+ * @return
+ */
+ public boolean flagAsExisting(GenericId id);
+
+ /**
+ * Checks whether the associated TOSA element exists
+ *
+ * @param id the id to check
+ * @return true iff the TOSCA element belonging to the given ID exists
+ */
+ public boolean exists(GenericId id);
+
+ /**
+ * Deletes the referenced object from the repository
+ *
+ * @param ref
+ */
+ public void forceDelete(RepositoryFileReference ref) throws IOException;
+
+ /**
+ * @param ref reference to check
+ * @return true if the file associated with the given reference exists
+ */
+ public boolean exists(RepositoryFileReference ref);
+
+ /**
+ * Puts the given content to the given file. Replaces existing content.
+ *
+ * If the parent of the reference does not exist, it is created.
+ *
+ * @param ref the reference to the file. Must not be null.
+ * @param content the content to put into the file. Must not be null.
+ * @param mediaType the media type of the file. Must not be null.
+ *
+ * @throws IOException if something goes wrong
+ */
+ public void putContentToFile(RepositoryFileReference ref, String content, MediaType mediaType) throws IOException;
+
+ /**
+ * Puts the given content to the given file. Replaces existing content.
+ *
+ * If the parent of the reference does not exist, it is created.
+ *
+ * @param ref the reference to the file
+ * @param content the content to put into the file
+ * @throws IOException if something goes wrong
+ */
+ public void putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) throws IOException;
+
+ /**
+ * Creates an opened inputStream of the contents referenced by ref. The
+ * stream has to be closed by the caller.
+ *
+ * @param ref the reference to the file
+ * @return an inputstream
+ * @throws IOException if something goes wrong
+ */
+ public InputStream newInputStream(RepositoryFileReference ref) throws IOException;
+
+ /**
+ * Returns the size of the file referenced by ref
+ *
+ * @param ref a refernce to the file stored in the repository
+ * @return the size in bytes
+ * @throws IOException if something goes wrong
+ */
+ long getSize(RepositoryFileReference ref) throws IOException;
+
+ /**
+ * Returns the last modification time of the entry.
+ *
+ * @param ref the reference to the file
+ * @return the time of the last modification
+ * @throws IOException if something goes wrong
+ */
+ FileTime getLastModifiedTime(RepositoryFileReference ref) throws IOException;
+
+ /**
+ * Returns the mimetype belonging to the reference.
+ *
+ * @param ref the reference to the file
+ * @return the mimetype as string
+ * @throws IOException if something goes wrong
+ * @throws IllegalStateException if an internal error occurs, which is not
+ * an IOException
+ */
+ String getMimeType(RepositoryFileReference ref) throws IOException;
+
+ /**
+ * @return the last change date of the file belonging to the given
+ * reference. NULL if the associated file does not exist.
+ */
+ Date getLastUpdate(RepositoryFileReference ref);
+
+ /**
+ * Returns all components available of the given id type
+ *
+ * @param idClass class of the Ids to search for
+ * @return empty set if no ids are available
+ */
+ public <T extends TOSCAComponentId> SortedSet<T> getAllTOSCAComponentIds(Class<T> idClass);
+
+ /**
+ * Returns the set of <em>all</em> ids nested in the given reference
+ *
+ * The generated Ids are linked as child to the id associated to the given
+ * reference
+ *
+ * Required for getting plans nested in a service template: plans are nested
+ * below the PlansOfOneServiceTemplateId
+ *
+ * @param ref a reference to the TOSCA element to be checked. The path
+ * belonging to this element is checked.
+ * @param idClass
+ * @return the set of Ids nested in the given reference. Empty set if there
+ * are no or the reference itself does not exist.
+ */
+ public <T extends TOSCAElementId> SortedSet<T> getNestedIds(GenericId ref, Class<T> idClass);
+
+ /**
+ * Returns the set of files nested in the given reference
+ */
+ public SortedSet<RepositoryFileReference> getContainedFiles(GenericId id);
+
+ /**
+ * Returns all namespaces used by all known TOSCA components
+ */
+ public Collection<Namespace> getUsedNamespaces();
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java
new file mode 100644
index 0000000..cb9560b
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepository.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import java.util.Date;
+
+import org.apache.commons.configuration.Configuration;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.GenericId;
+
+/**
+ * Provides interface to the backend.
+ *
+ * Currently a file-based backend is implemented. In the future, a git-based or
+ * a database-based backend is possible.
+ *
+ * The properties are managed by org.apache.commons.configuration. In case a new
+ * backend is added, the appropriate implementation of
+ * org.apache.commons.configuration.AbstrctConfiguration has to be chosen.
+ *
+ */
+public interface IRepository extends IGenericRepository {
+
+ /**
+ * Returns the configuration of the specified id
+ *
+ * If the associated TOSCA element does not exist, an empty configuration is
+ * returned. That means, the associated TOSCA element is created (SIDE
+ * EFFECT)
+ *
+ * The returned configuration ensures that autoSave is activated
+ *
+ * @param id may be a reference to a TOSCAcomponent or to a nested
+ * TOSCAelement
+ * @return a Configuration, where isAutoSave == true
+ */
+ Configuration getConfiguration(GenericId id);
+
+ /**
+ * Enables resources to define additional properties. Currently used for
+ * tags.
+ *
+ * Currently, more a quick hack. A generic TagsManager should be introduced
+ * to enable auto completion of tag names
+ *
+ * If the associated TOSCA element does not exist, an empty configuration is
+ * returned. That means, the associated TOSCA element is created (SIDE
+ * EFFECT)
+ */
+ Configuration getConfiguration(RepositoryFileReference ref);
+
+ /**
+ *
+ * @return the last change date of the configuration belonging to the given
+ * id. NULL if the associated TOSCA element does not exist.
+ */
+ Date getConfigurationLastUpdate(GenericId id);
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java
new file mode 100644
index 0000000..a373bdf
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/IRepositoryAdministration.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Interface for low-level repository administration
+ */
+public interface IRepositoryAdministration {
+
+ /**
+ * Dumps the content of the repository to the given output stream
+ *
+ * @param out stream to use to dump the data to. Currently, a ZIP output
+ * stream is returned.
+ * @throws IOException
+ */
+ void doDump(OutputStream out) throws IOException;
+
+ /**
+ * Removes all data
+ */
+ void doClear();
+
+ /**
+ * Imports the content of the given stream into the repsotiry.
+ *
+ * @param in the stream to use. Currently, only ZIP input is supported.
+ */
+ void doImport(InputStream in);
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java
new file mode 100644
index 0000000..8887cb2
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/MockXMLElement.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * Class for testing getAny()
+ *
+ * It has to be in src/main as src/test is not compiled during production, but
+ * the jaxbcontext is initialized in src/test and cannot be updated in src/main
+ *
+ * Included in {@link oorg.eclipse.winery.repository.JAXBSupport.initContext()}
+ */
+@XmlRootElement
+public class MockXMLElement {
+
+ @XmlElement
+ public String mock = "mock";
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java
new file mode 100644
index 0000000..f333005
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/Repository.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import org.eclipse.winery.repository.Prefs;
+
+public class Repository {
+
+ public final static IRepository INSTANCE = Prefs.INSTANCE.getRepository();
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java
new file mode 100644
index 0000000..2a75eba
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/ResourceCreationResult.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend;
+
+import java.net.URI;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.ids.GenericId;
+
+public class ResourceCreationResult {
+
+ private Status status = null;
+ private URI uri = null;
+ private GenericId id = null;
+
+
+ public ResourceCreationResult() {
+ }
+
+ public ResourceCreationResult(Status status) {
+ this.setStatus(status);
+ }
+
+ public ResourceCreationResult(Status status, URI uri, GenericId id) {
+ this.setStatus(status);
+ this.setId(id);
+ this.setUri(uri);
+ }
+
+ public Status getStatus() {
+ return this.status;
+ }
+
+ public void setStatus(Status status) {
+ this.status = status;
+ }
+
+ public URI getUri() {
+ return this.uri;
+ }
+
+ public void setUri(URI uri) {
+ this.uri = uri;
+ }
+
+ public GenericId getId() {
+ return this.id;
+ }
+
+ public void setId(GenericId id) {
+ this.id = id;
+ }
+
+ public boolean isSuccess() {
+ return this.getStatus() == Status.CREATED;
+ }
+
+ /**
+ * The possibly existing URI is used as location in Response.created
+ *
+ * @return a Response created based on the contained data
+ */
+ public Response getResponse() {
+ Response res;
+ if (this.getUri() == null) {
+ res = Response.status(this.getStatus()).build();
+ } else {
+ assert (this.getStatus().equals(Status.CREATED));
+ res = Response.created(this.getUri()).build();
+ }
+ return res;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java
new file mode 100644
index 0000000..23dc1b8
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/Filename.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.constants;
+
+/**
+ * TODO: check which of them can be removed
+ */
+public class Filename {
+
+ public static final String FILENAME_BIG_ICON = "bigIcon.png";
+ public static final String FILENAME_SMALL_ICON = "smallIcon.png";
+
+ public static final String FILENAME_JSON_NODETEMPLATES = "nodetemplates.json";
+ public static final String FILENAME_JSON_PARENTCACHE = "parents.json";
+ public static final String FILENAME_JSON_PLAN = "Plan.json";
+ public static final String FILENAME_JSON_RELATIONSHIPTEMPLATE = "realtionshiptemplates.json";
+ public static final String FILENAME_JSON_TOPOLOGYTEMPLATE = "TopologyTemplate.json";
+ public static final String FILENAME_JSON_OPERATION_WSDL = "wsdl.json";
+ public static final String FILENAME_JSON_OPERATION_REST = "rest.json";
+ public static final String FILENAME_JSON_OPERATION_SCRIPT = "script.json";
+ public static final String FILENAME_XML_PLAN = "Plan.xml";
+ public static final String FILENAME_PROPERTIES_ARTIFACT = "artifact.properties";
+ public static final String FILENAME_PROPERTIES_ARTIFACTTEMPLATE = "artifacttemplate.properties";
+ public static final String FILENAME_PROPERTIES_ARTIFACTTYPE = "artifacttype.properties";
+ public static final String FILENAME_PROPERTIES_FILEEXTENSIONTOARTIFACTTYPE = "fileextension-to-artifacttype.properties";
+ public static final String FILENAME_PROPERTIES_IMPORTS = "imports.properties";
+ public static final String FILENAME_PROPERTIES_NODETYPE = "NodeType.properties";
+ public static final String FILENAME_PROPERTIES_OPERATION = "operation.properties";
+ public static final String FILENAME_PROPERTIES_PLANCONTAINER = "plancontainer.properties";
+ public static final String FILENAME_PROPERTIES_PLANLANGUAGES = "planlanguages.properties";
+ public static final String FILENAME_PROPERTIES_PLANTYPES = "plantypes.properties";
+ public static final String FILENAME_PROPERTIES_PROPERTIES = "properties.properties";
+ public static final String FILENAME_PROPERTIES_RELATIONSHIPTYPE = "RelationshipType.properties";
+ public static final String FILENAME_PROPERTIES_SERVICETEMPLATE = "ServiceTemplate.properties";
+ public static final String FILENAME_PROPERTIES_TAGS = "tags.properties";
+ public static final String FILENAME_PROPERTIES_VISUALAPPEARANCE = "VisualAppearance.properties";
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java
new file mode 100644
index 0000000..46fe103
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/constants/MediaTypes.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.constants;
+
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.common.constants.MimeTypes;
+
+/**
+ * see also {@link org.eclipse.winery.common.constants.MimeTypes}
+ */
+public class MediaTypes {
+
+ public static final MediaType MEDIATYPE_TOSCA_DEFINITIONS = MediaType.valueOf(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS);
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java
new file mode 100644
index 0000000..ce330a1
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/AutoSaveListener.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.filebased;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.configuration.event.ConfigurationEvent;
+import org.apache.commons.configuration.event.ConfigurationListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * We do not count loads and saves as in
+ * {@link org.apache.commons.configuration.builder.AutoSaveListener}, because
+ * ConfigurationListener is not aware of such things
+ */
+class AutoSaveListener implements ConfigurationListener {
+
+ private static final Logger logger = LoggerFactory.getLogger(AutoSaveListener.class);
+
+ private final Path path;
+ private final PropertiesConfiguration configuration;
+
+
+ /**
+ *
+ * @param path the file path to write to
+ * @param configuration the configuration, where the change events come
+ * from. This is needed as <code>event.getSource()</code> does
+ * not work
+ */
+ public AutoSaveListener(Path path, PropertiesConfiguration configuration) {
+ this.path = path;
+ this.configuration = configuration;
+ }
+
+ @Override
+ public void configurationChanged(ConfigurationEvent event) {
+ if (!event.isBeforeUpdate()) {
+ try {
+ if (!Files.exists(this.path.getParent())) {
+ Files.createDirectories(this.path.getParent());
+ }
+ } catch (IOException ce) {
+ AutoSaveListener.logger.error("Could not update properties file", ce);
+ return;
+ }
+ try (OutputStream out = Files.newOutputStream(this.path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
+ OutputStreamWriter writer = new OutputStreamWriter(out);
+ this.configuration.save(writer);
+ } catch (ConfigurationException | IOException ce) {
+ AutoSaveListener.logger.error("Could not update properties file", ce);
+ }
+ }
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java
new file mode 100644
index 0000000..b970f96
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FileUtils.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.filebased;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class FileUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);
+
+
+ /**
+ * Deletes given path. If path a file, it is directly deleted. If it is a
+ * directory, the directory is recursively deleted.
+ *
+ * Does not try to change read-only files to read-write files
+ *
+ * Only uses Java7's nio, does not fall back to Java6.
+ *
+ * @param path the path to delete
+ * @throws IOException
+ */
+ public static void forceDelete(Path path) throws IOException {
+ if (Files.isDirectory(path)) {
+ try {
+ Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ try {
+ Files.delete(file);
+ } catch (IOException e) {
+ FileUtils.logger.debug("Could not delete file", e.getMessage());
+ }
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
+ if (exc == null) {
+ try {
+ Files.delete(dir);
+ } catch (IOException e) {
+ FileUtils.logger.debug("Could not delete dir", e);
+ }
+ return CONTINUE;
+ } else {
+ FileUtils.logger.debug("Could not delete file", exc);
+ return CONTINUE;
+ }
+ }
+ });
+ } catch (IOException e) {
+ FileUtils.logger.debug("Could not delete dir", e);
+ }
+ } else {
+ try {
+ Files.delete(path);
+ } catch (IOException e) {
+ FileUtils.logger.debug("Could not delete file", e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Creates the given directory including its parent directories, if they do
+ * not exist.
+ *
+ * @param path
+ * @throws IOException
+ */
+ public static void createDirectory(Path path) throws IOException {
+ Path parent = path.getParent();
+ if (parent == null) {
+ throw new IOException("No parent found");
+ }
+ if (!Files.exists(parent)) {
+ FileUtils.createDirectory(parent);
+ }
+ if (!Files.exists(path)) {
+ Files.createDirectory(path);
+ }
+ }
+
+ // public static Response readContentFromFile(RepositoryFileReference ref) {
+ // try {
+ // Repository.INSTANCE.readContentFromFile(ref);
+ // }
+ // }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java
new file mode 100644
index 0000000..6964681
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/FilebasedRepository.java
@@ -0,0 +1,596 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.filebased;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.charset.Charset;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.lang3.SystemUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
+import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.RequirementTypeId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.backend.AbstractRepository;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.IRepository;
+import org.eclipse.winery.repository.backend.IRepositoryAdministration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * When it comes to a storage of plain files, we use Java 7's nio internally.
+ * Therefore, we intend to expose the stream types offered by java.nio.Files:
+ * BufferedReader/BufferedWriter
+ */
+public class FilebasedRepository extends AbstractRepository implements IRepository, IRepositoryAdministration {
+
+ private static final Logger logger = LoggerFactory.getLogger(FilebasedRepository.class);
+
+ protected final Path repositoryRoot;
+
+ // convenience variables to have a clean code
+ private final FileSystem fileSystem;
+ private final FileSystemProvider provider;
+
+
+ private Path makeAbsolute(Path relativePath) {
+ return this.repositoryRoot.resolve(relativePath);
+ }
+
+ @Override
+ public boolean flagAsExisting(GenericId id) {
+ Path path = this.id2AbsolutePath(id);
+ try {
+ FileUtils.createDirectory(path);
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug(e.toString());
+ return false;
+ }
+ return true;
+ }
+
+ private Path id2AbsolutePath(GenericId id) {
+ Path relativePath = this.fileSystem.getPath(BackendUtils.getPathInsideRepo(id));
+ return this.makeAbsolute(relativePath);
+ }
+
+ /**
+ * Converts the given reference to an absolute path of the underlying
+ * FileSystem
+ */
+ public Path ref2AbsolutePath(RepositoryFileReference ref) {
+ return this.id2AbsolutePath(ref.getParent()).resolve(ref.getFileName());
+ }
+
+ /**
+ *
+ * @param repositoryLocation a string pointing to a location on the file
+ * system. May be null.
+ */
+ public FilebasedRepository(String repositoryLocation) {
+ this.repositoryRoot = this.determineRepositoryPath(repositoryLocation);
+ this.fileSystem = this.repositoryRoot.getFileSystem();
+ this.provider = this.fileSystem.provider();
+ }
+
+ private Path determineRepositoryPath(String repositoryLocation) {
+ Path repositoryPath;
+ if (repositoryLocation == null) {
+ if (SystemUtils.IS_OS_WINDOWS) {
+ if (new File(Constants.GLOBAL_REPO_PATH_WINDOWS).exists()) {
+ repositoryLocation = Constants.GLOBAL_REPO_PATH_WINDOWS;
+ File repo = new File(repositoryLocation);
+ try {
+ org.apache.commons.io.FileUtils.forceMkdir(repo);
+ } catch (IOException e) {
+ FilebasedRepository.logger.error("Could not create repository directory", e);
+ }
+ repositoryPath = repo.toPath();
+ } else {
+ repositoryPath = this.createDefaultRepositoryPath();
+ }
+ } else {
+ repositoryPath = this.createDefaultRepositoryPath();
+ }
+ } else {
+ File repo = new File(repositoryLocation);
+ try {
+ org.apache.commons.io.FileUtils.forceMkdir(repo);
+ } catch (IOException e) {
+ FilebasedRepository.logger.error("Could not create repository directory", e);
+ }
+ repositoryPath = repo.toPath();
+ }
+ return repositoryPath;
+ }
+
+ public static File getDefaultRepositoryFilePath() {
+ return new File(org.apache.commons.io.FileUtils.getUserDirectory(), Constants.DEFAULT_REPO_NAME);
+ }
+
+ private Path createDefaultRepositoryPath() {
+ File repo = null;
+ boolean operationalFileSystemAccess;
+ try {
+ repo = FilebasedRepository.getDefaultRepositoryFilePath();
+ operationalFileSystemAccess = true;
+ } catch (NullPointerException e) {
+ // it seems, we run at a system, where we do not have any filesystem
+ // access
+ operationalFileSystemAccess = false;
+ }
+
+ // operationalFileSystemAccess = false;
+
+ Path repositoryPath;
+ if (operationalFileSystemAccess) {
+ try {
+ org.apache.commons.io.FileUtils.forceMkdir(repo);
+ } catch (IOException e) {
+ FilebasedRepository.logger.error("Could not create directory", e);
+ }
+ repositoryPath = repo.toPath();
+ } else {
+ assert (!operationalFileSystemAccess);
+ // we do not have access to the file system
+ throw new IllegalStateException("No write access to file system");
+ }
+
+ return repositoryPath;
+ }
+
+ @Override
+ public void forceDelete(RepositoryFileReference ref) throws IOException {
+ Path relativePath = this.fileSystem.getPath(BackendUtils.getPathInsideRepo(ref));
+ Path fileToDelete = this.makeAbsolute(relativePath);
+ try {
+ this.provider.delete(fileToDelete);
+ // Quick hack for deletion of the mime type information
+ // Alternative: superclass: protected void deleteMimeTypeInformation(RepositoryFileReference ref) throws IOException
+ // However, this would again call this method, where we would have to check for the extension, too.
+ // Therefore, we directly delete the information file
+ Path mimeTypeFile = fileToDelete.getParent().resolve(ref.getFileName() + Constants.SUFFIX_MIMETYPE);
+ this.provider.delete(mimeTypeFile);
+ } catch (IOException e) {
+ if (!(e instanceof NoSuchFileException)) {
+ // only if file did exist and something else went wrong: complain :)
+ // (otherwise, silently ignore the error)
+ FilebasedRepository.logger.debug("Could not delete file", e);
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public void forceDelete(GenericId id) throws IOException {
+ try {
+ FileUtils.forceDelete(this.id2AbsolutePath(id));
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug("Could not delete id", id);
+ throw e;
+ }
+ }
+
+ @Override
+ public boolean exists(GenericId id) {
+ Path absolutePath = this.id2AbsolutePath(id);
+ boolean result = Files.exists(absolutePath);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putContentToFile(RepositoryFileReference ref, String content, MediaType mediaType) throws IOException {
+ if (mediaType == null) {
+ // quick hack for storing mime type called this method
+ assert (ref.getFileName().endsWith(Constants.SUFFIX_MIMETYPE));
+ // we do not need to store the mime type of the file containing the mime type information
+ } else {
+ this.setMimeType(ref, mediaType);
+ }
+ Path path = this.ref2AbsolutePath(ref);
+ FileUtils.createDirectory(path.getParent());
+ Files.write(path, content.getBytes());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putContentToFile(RepositoryFileReference ref, InputStream inputStream, MediaType mediaType) throws IOException {
+ if (mediaType == null) {
+ // quick hack for storing mime type called this method
+ assert (ref.getFileName().endsWith(Constants.SUFFIX_MIMETYPE));
+ // we do not need to store the mime type of the file containing the mime type information
+ } else {
+ this.setMimeType(ref, mediaType);
+ }
+ Path targetPath = this.ref2AbsolutePath(ref);
+ // ensure that parent directory exists
+ FileUtils.createDirectory(targetPath.getParent());
+
+ try {
+ Files.copy(inputStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
+ } catch (IllegalStateException e) {
+ FilebasedRepository.logger.debug("Guessing that stream with length 0 is to be written to a file", e);
+ // copy throws an "java.lang.IllegalStateException: Stream already closed" if the InputStream contains 0 bytes
+ // For instance, this case happens if SugarCE-6.4.2.zip.removed is tried to be uploaded
+ // We work around the Java7 issue and create an empty file
+ if (Files.exists(targetPath)) {
+ // semantics of putContentToFile: existing content is replaced without notification
+ Files.delete(targetPath);
+ }
+ Files.createFile(targetPath);
+ }
+ }
+
+ @Override
+ public boolean exists(RepositoryFileReference ref) {
+ return Files.exists(this.ref2AbsolutePath(ref));
+ }
+
+ @Override
+ public <T extends TOSCAComponentId> SortedSet<T> getAllTOSCAComponentIds(Class<T> idClass) {
+ SortedSet<T> res = new TreeSet<T>();
+ String rootPathFragment = Util.getRootPathFragment(idClass);
+ Path dir = this.repositoryRoot.resolve(rootPathFragment);
+ if (!Files.exists(dir)) {
+ // return empty list if no ids are available
+ return res;
+ }
+ assert (Files.isDirectory(dir));
+
+ final OnlyNonHiddenDirectories onhdf = new OnlyNonHiddenDirectories();
+
+ // list all directories contained in this directory
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, onhdf)) {
+ for (Path nsP : ds) {
+ // the current path is the namespace
+ Namespace ns = new Namespace(nsP.getFileName().toString(), true);
+ try (DirectoryStream<Path> idDS = Files.newDirectoryStream(nsP, onhdf)) {
+ for (Path idP : idDS) {
+ XMLId xmlId = new XMLId(idP.getFileName().toString(), true);
+ Constructor<T> constructor;
+ try {
+ constructor = idClass.getConstructor(Namespace.class, XMLId.class);
+ } catch (Exception e) {
+ FilebasedRepository.logger.debug("Internal error at determining id constructor", e);
+ // abort everything, return invalid result
+ return res;
+ }
+ T id;
+ try {
+ id = constructor.newInstance(ns, xmlId);
+ } catch (InstantiationException
+ | IllegalAccessException
+ | IllegalArgumentException
+ | InvocationTargetException e) {
+ FilebasedRepository.logger.debug("Internal error at invocation of id constructor", e);
+ // abort everything, return invalid result
+ return res;
+ }
+ res.add(id);
+ }
+ }
+ }
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug("Cannot close ds", e);
+ }
+
+ return res;
+ }
+
+ @Override
+ public SortedSet<RepositoryFileReference> getContainedFiles(GenericId id) {
+ Path dir = this.id2AbsolutePath(id);
+ SortedSet<RepositoryFileReference> res = new TreeSet<RepositoryFileReference>();
+ if (!Files.exists(dir)) {
+ return res;
+ }
+ assert (Files.isDirectory(dir));
+ // list all directories contained in this directory
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, new OnlyNonHiddenFiles())) {
+ for (Path p : ds) {
+ RepositoryFileReference ref = new RepositoryFileReference(id, p.getFileName().toString());
+ res.add(ref);
+ }
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug("Cannot close ds", e);
+ }
+ return res;
+ }
+
+ @Override
+ public Configuration getConfiguration(RepositoryFileReference ref) {
+ Path path = this.ref2AbsolutePath(ref);
+
+ PropertiesConfiguration configuration = new PropertiesConfiguration();
+ if (Files.exists(path)) {
+ try (Reader r = Files.newBufferedReader(path, Charset.defaultCharset())) {
+ configuration.load(r);
+ } catch (ConfigurationException | IOException e) {
+ FilebasedRepository.logger.error("Could not read config file", e);
+ throw new IllegalStateException("Could not read config file", e);
+ }
+ }
+
+ configuration.addConfigurationListener(new AutoSaveListener(path, configuration));
+
+ // We do NOT implement reloading as the configuration is only accessed
+ // in JAX-RS resources, which are created on a per-request basis
+
+ return configuration;
+ }
+
+ /**
+ * @return null if an error occurred
+ */
+ @Override
+ public Date getLastUpdate(RepositoryFileReference ref) {
+ Path path = this.ref2AbsolutePath(ref);
+ Date res;
+ if (Files.exists(path)) {
+ FileTime lastModifiedTime;
+ try {
+ lastModifiedTime = Files.getLastModifiedTime(path);
+ res = new Date(lastModifiedTime.toMillis());
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug(e.getMessage(), e);
+ res = null;
+ }
+ } else {
+ // this branch is taken if the resource directory exists, but the
+ // configuration itself does not exist.
+ // For instance, this happens if icons are manually put for a node
+ // type, but no color configuration is made.
+ res = Constants.LASTMODIFIEDDATE_FOR_404;
+ }
+ return res;
+ }
+
+ @Override
+ public <T extends TOSCAElementId> SortedSet<T> getNestedIds(GenericId ref, Class<T> idClass) {
+ Path dir = this.id2AbsolutePath(ref);
+ SortedSet<T> res = new TreeSet<T>();
+ if (!Files.exists(dir)) {
+ // the id has been generated by the exporter without existance test.
+ // This test is done here.
+ return res;
+ }
+ assert (Files.isDirectory(dir));
+ // list all directories contained in this directory
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, new OnlyNonHiddenDirectories())) {
+ for (Path p : ds) {
+ XMLId xmlId = new XMLId(p.getFileName().toString(), true);
+ @SuppressWarnings("unchecked")
+ Constructor<T>[] constructors = (Constructor<T>[]) idClass.getConstructors();
+ assert (constructors.length == 1);
+ Constructor<T> constructor = constructors[0];
+ assert (constructor.getParameterTypes().length == 2);
+ T id;
+ try {
+ id = constructor.newInstance(ref, xmlId);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ FilebasedRepository.logger.debug("Internal error at invocation of id constructor", e);
+ // abort everything, return invalid result
+ return res;
+ }
+ res.add(id);
+ }
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug("Cannot close ds", e);
+ }
+ return res;
+ }
+
+ @Override
+ // below, toscaComponents is an array, which is used in an iterator
+ // As Java does not allow generic arrays, we have to suppress the warning when fetching an element out of the list
+ @SuppressWarnings("unchecked")
+ public Collection<Namespace> getUsedNamespaces() {
+ // @formatter:off
+ @SuppressWarnings("rawtypes")
+ Class[] toscaComponentIds = {
+ ArtifactTemplateId.class,
+ ArtifactTypeId.class,
+ CapabilityTypeId.class,
+ NodeTypeId.class,
+ NodeTypeImplementationId.class,
+ PolicyTemplateId.class,
+ PolicyTypeId.class,
+ RelationshipTypeId.class,
+ RelationshipTypeImplementationId.class,
+ RequirementTypeId.class,
+ ServiceTemplateId.class
+ };
+ // @formatter:on
+
+ // we use a HashSet to avoid reporting duplicate namespaces
+ Collection<Namespace> res = new HashSet<Namespace>();
+
+ for (Class<? extends TOSCAComponentId> id : toscaComponentIds) {
+ String rootPathFragment = Util.getRootPathFragment(id);
+ Path dir = this.repositoryRoot.resolve(rootPathFragment);
+ if (!Files.exists(dir)) {
+ continue;
+ }
+ assert (Files.isDirectory(dir));
+
+ final OnlyNonHiddenDirectories onhdf = new OnlyNonHiddenDirectories();
+
+ // list all directories contained in this directory
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, onhdf)) {
+ for (Path nsP : ds) {
+ // the current path is the namespace
+ Namespace ns = new Namespace(nsP.getFileName().toString(), true);
+ res.add(ns);
+ }
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug("Cannot close ds", e);
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public void doDump(OutputStream out) throws IOException {
+ final ZipOutputStream zout = new ZipOutputStream(out);
+ final int cutLength = this.repositoryRoot.toString().length() + 1;
+
+ Files.walkFileTree(this.repositoryRoot, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ if (dir.endsWith(".git")) {
+ return FileVisitResult.SKIP_SUBTREE;
+ } else {
+ return FileVisitResult.CONTINUE;
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ String name = file.toString().substring(cutLength);
+ ZipEntry ze = new ZipEntry(name);
+ try {
+ ze.setTime(Files.getLastModifiedTime(file).toMillis());
+ ze.setSize(Files.size(file));
+ zout.putNextEntry(ze);
+ Files.copy(file, zout);
+ zout.closeEntry();
+ } catch (IOException e) {
+ FilebasedRepository.logger.debug(e.getMessage());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ zout.close();
+ }
+
+ /**
+ * Removes all files and dirs except the .git directory
+ */
+ @Override
+ public void doClear() {
+ try {
+ DirectoryStream.Filter<Path> noGitDirFilter = new DirectoryStream.Filter<Path>() {
+
+ @Override
+ public boolean accept(Path entry) throws IOException {
+ return !(entry.getFileName().toString().equals(".git"));
+ }
+ };
+
+ DirectoryStream<Path> ds = Files.newDirectoryStream(this.repositoryRoot, noGitDirFilter);
+ for (Path p : ds) {
+ FileUtils.forceDelete(p);
+ }
+ } catch (IOException e) {
+ FilebasedRepository.logger.error(e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void doImport(InputStream in) {
+ ZipInputStream zis = new ZipInputStream(in);
+ ZipEntry entry;
+ try {
+ while ((entry = zis.getNextEntry()) != null) {
+ if (!entry.isDirectory()) {
+ Path path = this.repositoryRoot.resolve(entry.getName());
+ FileUtils.createDirectory(path.getParent());
+ Files.copy(zis, path);
+ }
+ }
+ } catch (IOException e) {
+ FilebasedRepository.logger.error(e.getMessage());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getSize(RepositoryFileReference ref) throws IOException {
+ return Files.size(this.ref2AbsolutePath(ref));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public FileTime getLastModifiedTime(RepositoryFileReference ref) throws IOException {
+ Path path = this.ref2AbsolutePath(ref);
+ FileTime res = Files.getLastModifiedTime(path);
+ return res;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public InputStream newInputStream(RepositoryFileReference ref) throws IOException {
+ Path path = this.ref2AbsolutePath(ref);
+ InputStream res = Files.newInputStream(path);
+ return res;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java
new file mode 100644
index 0000000..a3f3fc8
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.filebased;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.eclipse.jgit.api.AddCommand;
+import org.eclipse.jgit.api.CleanCommand;
+import org.eclipse.jgit.api.CommitCommand;
+import org.eclipse.jgit.api.FetchCommand;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.api.PushCommand;
+import org.eclipse.jgit.api.ResetCommand;
+import org.eclipse.jgit.api.ResetCommand.ResetType;
+import org.eclipse.jgit.api.errors.CheckoutConflictException;
+import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.api.errors.NoHeadException;
+import org.eclipse.jgit.api.errors.NoMessageException;
+import org.eclipse.jgit.api.errors.UnmergedPathsException;
+import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
+import org.eclipse.jgit.transport.CredentialsProvider;
+import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
+import org.eclipse.winery.repository.Prefs;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used for testing only.
+ *
+ * Allows to reset repository to a certain commit id
+ */
+public class GitBasedRepository extends FilebasedRepository {
+
+ private static final Logger logger = LoggerFactory.getLogger(GitBasedRepository.class);
+
+ private final Repository gitRepo;
+ private final Git git;
+ private final CredentialsProvider cp;
+
+ public static final String PREFERENCE_GIT_USERNAME = "git.username";
+ public static final String PREFERENCE_GIT_PASSWORD = "git.password";
+
+
+ /**
+ * @param repositoryLocation the location of the repository
+ * @throws IOException thrown if repository does not exist
+ */
+ public GitBasedRepository(String repositoryLocation) throws IOException {
+ super(repositoryLocation);
+ FileRepositoryBuilder builder = new FileRepositoryBuilder();
+ this.gitRepo = builder.setWorkTree(this.repositoryRoot.toFile()).setMustExist(true).build();
+ this.git = new Git(this.gitRepo);
+
+ this.cp = this.initializeCredentialsProvider();
+ }
+
+ /**
+ * Reads the properties stored in ".winery" in the repository
+ */
+ private Properties dotWineryProperties() {
+ Properties p = new Properties();
+ File f = new File(this.repositoryRoot.toFile(), ".winery");
+ InputStream is;
+ try {
+ is = new FileInputStream(f);
+ } catch (FileNotFoundException e1) {
+ // .winery does not exist in the file-based repository
+ return p;
+ }
+ if (is != null) {
+ try {
+ p.load(is);
+ } catch (IOException e) {
+ GitBasedRepository.logger.debug(e.getMessage(), e);
+ }
+ }
+ return p;
+ }
+
+ /**
+ * Uses git.username und git.password from .winery and winery.properties
+ *
+ * Considering .winery is useful if the same war file is used on a dev
+ * server and a stable server. The WAR file cannot contain the credentials
+ * if committing is only allowed on only one of these servers
+ */
+ private CredentialsProvider initializeCredentialsProvider() {
+ CredentialsProvider cp;
+
+ Properties wp = this.dotWineryProperties();
+
+ String gitUserName = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME);
+ if (gitUserName == null) {
+ gitUserName = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME);
+ }
+
+ String gitPassword = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD);
+ if (gitPassword == null) {
+ gitPassword = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD);
+ }
+
+ if (gitUserName == null) {
+ cp = null;
+ } else if (gitPassword == null) {
+ cp = null;
+ } else {
+ cp = new UsernamePasswordCredentialsProvider(gitUserName, gitPassword);
+ }
+ return cp;
+ }
+
+ public void addCommitPush() throws NoHeadException, NoMessageException, UnmergedPathsException, ConcurrentRefUpdateException, WrongRepositoryStateException, GitAPIException {
+ AddCommand add = this.git.add();
+ add.addFilepattern(".");
+ add.call();
+
+ CommitCommand commit = this.git.commit();
+ commit.setMessage("Commit through Winery");
+ commit.call();
+
+ PushCommand push = this.git.push();
+ if (this.cp != null) {
+ push.setCredentialsProvider(this.cp);
+ }
+ push.call();
+ }
+
+ private void clean() throws NoWorkTreeException, GitAPIException {
+ GitBasedRepository.logger.trace("git clean");
+ // remove untracked files
+ CleanCommand clean = this.git.clean();
+ clean.setCleanDirectories(true);
+ clean.call();
+ }
+
+ public void cleanAndResetHard() throws NoWorkTreeException, GitAPIException {
+ // enable updating by resetting the content of the repository
+ this.clean();
+
+ // fetch the newest thing from upstream
+ GitBasedRepository.logger.trace("git fetch");
+ FetchCommand fetch = this.git.fetch();
+ if (this.cp != null) {
+ fetch.setCredentialsProvider(this.cp);
+ }
+ fetch.call();
+
+ // after fetching, reset to the latest version
+ GitBasedRepository.logger.trace("git reset --hard");
+ ResetCommand reset = this.git.reset();
+ reset.setMode(ResetType.HARD);
+ reset.call();
+ }
+
+ public void setRevisionTo(String ref) throws CheckoutConflictException, GitAPIException {
+ this.clean();
+
+ // reset repository to the desired reference
+ ResetCommand reset = this.git.reset();
+ reset.setMode(ResetType.HARD);
+ reset.setRef(ref);
+ reset.call();
+ }
+
+ /**
+ * Returns true if authentification information (for instance, to push to
+ * upstream) is available
+ */
+ public boolean authenticationInfoAvailable() {
+ return this.cp != null;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java
new file mode 100644
index 0000000..a5acd8e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenDirectories.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.filebased;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public class OnlyNonHiddenDirectories implements DirectoryStream.Filter<Path> {
+
+ @Override
+ public boolean accept(Path entry) throws IOException {
+ // we return only non-hidden directories
+ // E.g., DS_Store of Mac OS X is a hidden directory
+ return Files.isDirectory(entry) && !Files.isHidden(entry);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java
new file mode 100644
index 0000000..3b788b4
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/OnlyNonHiddenFiles.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.backend.filebased;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.winery.repository.Constants;
+
+/**
+ * Only non-hidden files. Also excludes file names ending with
+ * Constants.SUFFIX_MIMETYPE
+ */
+public class OnlyNonHiddenFiles implements DirectoryStream.Filter<Path> {
+
+ @Override
+ public boolean accept(Path entry) throws IOException {
+ // we return only non-hidden files
+ // and we do not return the file "FN.mimetype", which are used to store the mimetype of FN
+ return !Files.isDirectory(entry) && !Files.isHidden(entry) && (!entry.getFileName().toString().endsWith(Constants.SUFFIX_MIMETYPE));
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java
new file mode 100644
index 0000000..bf25ae7
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/FileMeta.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes;
+
+import java.io.IOException;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.commons.io.FilenameUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.Prefs;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * based on
+ * https://github.com/blueimp/jQuery-File-Upload/wiki/Google-App-Engine-Java
+ *
+ * The getters are named according to the requirements of the template in
+ * jquery-file-upload-full.jsp
+ */
+@XmlRootElement
+public class FileMeta {
+
+ private static final Logger logger = LoggerFactory.getLogger(FileMeta.class);
+
+ String name;
+ long size;
+ String url;
+ String deleteUrl;
+ String deleteType = "DELETE";
+ String thumbnailUrl;
+
+
+ public String getName() {
+ return this.name;
+ }
+
+ public long getSize() {
+ return this.size;
+ }
+
+ public String getUrl() {
+ return this.url;
+ }
+
+ public String getDeleteUrl() {
+ return this.deleteUrl;
+ }
+
+ public String getDeleteType() {
+ return this.deleteType;
+ }
+
+ public String getThumbnailUrl() {
+ return this.thumbnailUrl;
+ }
+
+ public FileMeta(String filename, long size, String url, String thumbnailUrl) {
+ this.name = filename;
+ this.size = size;
+ this.url = url;
+ this.thumbnailUrl = thumbnailUrl;
+ this.deleteUrl = url;
+ }
+
+ public FileMeta(RepositoryFileReference ref) {
+ this.name = ref.getFileName();
+ try {
+ this.size = Repository.INSTANCE.getSize(ref);
+ } catch (IOException e) {
+ FileMeta.logger.error(e.getMessage(), e);
+ this.size = 0;
+ }
+ this.url = Utils.getAbsoluteURL(ref);
+ this.deleteUrl = this.url;
+ this.thumbnailUrl = Prefs.INSTANCE.getResourcePath() + Constants.PATH_MIMETYPEIMAGES + FilenameUtils.getExtension(this.name) + Constants.SUFFIX_MIMETYPEIMAGES;
+ }
+
+ /**
+ * @param ref the reference to get information from
+ * @param URLprefix the string which should be prepended the actual URL.
+ * Including the "/"
+ */
+ public FileMeta(RepositoryFileReference ref, String URLprefix) {
+ this(ref);
+ this.url = URLprefix + this.url;
+ }
+
+ /**
+ * The constructor is used for JAX-B only. Therefore, the warning "unused"
+ * is suppressed
+ */
+ @SuppressWarnings("unused")
+ private FileMeta() {
+ }
+
+} \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java
new file mode 100644
index 0000000..eae201d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/TypeWithShortName.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes;
+
+public class TypeWithShortName implements Comparable<TypeWithShortName> {
+
+ private final String type;
+ // we could have used "URI" as type here but this seems to be unnecessary
+ // overhead
+
+ // this is a kind of ID
+ private final String shortName;
+
+
+ public TypeWithShortName(String type, String shortName) {
+ this.type = type;
+ this.shortName = shortName;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public String getShortName() {
+ return this.shortName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof TypeWithShortName) {
+ return ((TypeWithShortName) o).getType().equals(this.getType());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getType().hashCode();
+ }
+
+ @Override
+ public int compareTo(TypeWithShortName o) {
+ int c = this.getShortName().compareTo(o.getShortName());
+ if (c == 0) {
+ // not sure if this will ever happen
+ c = this.getType().compareTo(o.getType());
+ }
+ return c;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java
new file mode 100644
index 0000000..f06c917
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/IdNames.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids;
+
+/**
+ * This class is the brother of {@link org.eclipse.winery.common.id.IdNames}
+ *
+ * It includes all id names used additionally in the local ids
+ */
+public class IdNames {
+
+ // the files belonging to one artifact template are nested in the sub
+ // directory "files"
+ public static final String ARTIFACTTEMPLATEDIRECTORY = "files";
+
+ public static final String CONSTRAINTTYPES = "constrainttypes";
+ public static final String NAMESPACES = "namespaces";
+ public static final String PLANLANGUAGES = "planlanguages";
+ public static final String PLANTYPES = "plantypes";
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java
new file mode 100644
index 0000000..3a31b05
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/AdminId.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.admin;
+
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.common.ids.XMLId;
+
+/**
+ * The Id for the single admin resource holding administrative things such as
+ * the prefixes of namespaces
+ */
+public abstract class AdminId extends GenericId {
+
+ protected AdminId(XMLId xmlId) {
+ super(xmlId);
+ }
+
+ @Override
+ public int compareTo(GenericId o) {
+ if (o instanceof AdminId) {
+ return this.getXmlId().compareTo(o.getXmlId());
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public GenericId getParent() {
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof AdminId) {
+ return this.getXmlId().equals(((AdminId) obj).getXmlId());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return this.getXmlId().hashCode();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java
new file mode 100644
index 0000000..210a2c7
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/ConstraintTypesId.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.admin;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.repository.datatypes.ids.IdNames;
+
+public class ConstraintTypesId extends TypesId {
+
+ private final static XMLId xmlId = new XMLId(IdNames.CONSTRAINTTYPES, false);
+
+
+ public ConstraintTypesId() {
+ super(ConstraintTypesId.xmlId);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java
new file mode 100644
index 0000000..4bdb233
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/NamespacesId.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.admin;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.repository.datatypes.ids.IdNames;
+
+public class NamespacesId extends AdminId {
+
+ private final static XMLId xmlId = new XMLId(IdNames.NAMESPACES, false);
+
+
+ public NamespacesId() {
+ super(NamespacesId.xmlId);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java
new file mode 100644
index 0000000..7ebfb7d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanLanguagesId.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.admin;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.repository.datatypes.ids.IdNames;
+
+public class PlanLanguagesId extends TypesId {
+
+ private final static XMLId xmlId = new XMLId(IdNames.PLANLANGUAGES, false);
+
+
+ public PlanLanguagesId() {
+ super(PlanLanguagesId.xmlId);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java
new file mode 100644
index 0000000..e44cd2b
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/PlanTypesId.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.admin;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.repository.datatypes.ids.IdNames;
+
+public class PlanTypesId extends TypesId {
+
+ private final static XMLId xmlId = new XMLId(IdNames.PLANTYPES, false);
+
+
+ public PlanTypesId() {
+ super(PlanTypesId.xmlId);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java
new file mode 100644
index 0000000..db40780
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/admin/TypesId.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.admin;
+
+import org.eclipse.winery.common.ids.XMLId;
+
+public abstract class TypesId extends AdminId {
+
+ protected TypesId(XMLId xmlId) {
+ super(xmlId);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java
new file mode 100644
index 0000000..cce2d53
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/ArtifactTemplateDirectoryId.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.elements;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+import org.eclipse.winery.repository.datatypes.ids.IdNames;
+
+public class ArtifactTemplateDirectoryId extends TOSCAElementId {
+
+ private final static XMLId xmlID = new XMLId(IdNames.ARTIFACTTEMPLATEDIRECTORY, false);
+
+
+ public ArtifactTemplateDirectoryId(ArtifactTemplateId parent) {
+ super(parent, ArtifactTemplateDirectoryId.xmlID);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java
new file mode 100644
index 0000000..6bd5db8
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/SelfServiceMetaDataId.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.elements;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+
+public class SelfServiceMetaDataId extends TOSCAElementId {
+
+ public SelfServiceMetaDataId(ServiceTemplateId parent) {
+ super(parent, new XMLId("SELFSERVICE-Metadata", true));
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java
new file mode 100644
index 0000000..9b7784f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/ids/elements/VisualAppearanceId.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.ids.elements;
+
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+
+/**
+ * ID for a pseudo-TOSCA-Element holding the data for the visual appearance
+ * (e.g., icons for node types)
+ */
+public class VisualAppearanceId extends TOSCAElementId {
+
+ public VisualAppearanceId(TopologyGraphElementEntityTypeId parent) {
+ super(parent, new XMLId("appearance", true));
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java
new file mode 100644
index 0000000..1b8fb9a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataItem.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.select2;
+
+/**
+ * Models a data item for select2. In case optgroups have to be returned, use
+ * this element in a TreeMap
+ */
+public class Select2DataItem implements Comparable<Select2DataItem> {
+
+ private final String id;
+ private final String text;
+
+
+ public Select2DataItem(String id, String text) {
+ this.id = id;
+ this.text = text;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public String getText() {
+ return this.text;
+ }
+
+ /**
+ * Sort order is based on text
+ */
+ @Override
+ public int compareTo(Select2DataItem o) {
+ return this.getText().compareTo(o.getText());
+ }
+
+ /**
+ * Equality is checked at id level
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Select2DataItem)) {
+ return false;
+ }
+ return this.getId().equals(((Select2DataItem) o).getId());
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java
new file mode 100644
index 0000000..50e5ecd
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2DataWithOptGroups.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.select2;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class Select2DataWithOptGroups {
+
+ Map<String, Select2OptGroup> idx = new HashMap<>();
+
+
+ /**
+ * Add an item to a group
+ *
+ * @param group the group
+ * @param id the id of the item
+ * @param text the text of the item {@inheritDoc}
+ */
+ public void add(String group, String id, String text) {
+ Select2OptGroup optGroup = this.idx.get(group);
+ if (optGroup == null) {
+ optGroup = new Select2OptGroup(group);
+ this.idx.put(group, optGroup);
+ }
+
+ Select2DataItem item = new Select2DataItem(id, text);
+ optGroup.addItem(item);
+ }
+
+ public SortedSet<Select2OptGroup> asSortedSet() {
+ // convert the index to the real result
+ SortedSet<Select2OptGroup> res = new TreeSet<>();
+ for (Select2OptGroup optGroup : this.idx.values()) {
+ res.add(optGroup);
+ }
+
+ return res;
+
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java
new file mode 100644
index 0000000..7a7a88b
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/Select2OptGroup.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.datatypes.select2;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class Select2OptGroup implements Comparable<Select2OptGroup> {
+
+ private final String text;
+ private final SortedSet<Select2DataItem> children;
+
+
+ public Select2OptGroup(String text) {
+ this.text = text;
+ this.children = new TreeSet<Select2DataItem>();
+ }
+
+ public String getText() {
+ return this.text;
+ }
+
+ /**
+ * Returns the internal SortedSet for data items.
+ */
+ public SortedSet<Select2DataItem> getChildren() {
+ return this.children;
+ }
+
+ public void addItem(Select2DataItem item) {
+ this.children.add(item);
+ }
+
+ /**
+ * Quick hack to test Select2OptGroups for equality. Only the text is
+ * tested, not the contained children. This might cause issues later, but
+ * currently not.
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Select2OptGroup)) {
+ return false;
+ }
+ return this.text.equals(((Select2OptGroup) o).text);
+ }
+
+ /**
+ * Quick hack to compare Select2OptGroups. Only the text is compared, not
+ * the contained children. This might cause issues later, but currently not.
+ */
+ @Override
+ public int compareTo(Select2OptGroup o) {
+ return this.getText().compareTo(o.getText());
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java
new file mode 100644
index 0000000..ee1fbaf
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/datatypes/select2/package-info.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+/**
+ * This package collects all datatypes required to generate valid select2 data objects
+ * {@see http://ivaynberg.github.io/select2/}: Example Hierarchical Data
+ */
+package org.eclipse.winery.repository.datatypes.select2; \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java
new file mode 100644
index 0000000..ac27478
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/CSARExporter.java
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Kálmán Képes - initial API and implementation and/or initial documentation
+ * Oliver Kopp - adapted to new storage model and to TOSCA v1.0
+ *******************************************************************************/
+package org.eclipse.winery.repository.export;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.JAXBException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.commons.compress.archivers.ArchiveEntry;
+import org.apache.commons.compress.archivers.ArchiveException;
+import org.apache.commons.compress.archivers.ArchiveOutputStream;
+import org.apache.commons.compress.archivers.ArchiveStreamFactory;
+import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.io.IOUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.constants.MimeTypes;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.model.selfservice.Application;
+import org.eclipse.winery.model.selfservice.Application.Options;
+import org.eclipse.winery.model.selfservice.ApplicationOption;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.Prefs;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.admin.NamespacesId;
+import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId;
+import org.eclipse.winery.repository.resources.admin.NamespacesResource;
+import org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal.SelfServicePortalResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+/**
+ * This class exports a CSAR crawling from the the given GenericId<br/>
+ * Currently, only ServiceTemplates are supported<br />
+ * commons-compress is used as an output stream should be provided. An
+ * alternative implementation is to use Java7's Zip File System Provider
+ */
+public class CSARExporter {
+
+ public static final String PATH_TO_NAMESPACES_PROPERTIES = "winery/Namespaces.properties";
+
+ private static final Logger logger = LoggerFactory.getLogger(CSARExporter.class);
+
+ private static final String DEFINITONS_PATH_PREFIX = "Definitions/";
+
+
+ /**
+ * Returns a unique name for the given definitions to be used as filename
+ */
+ private static String getDefinitionsName(TOSCAComponentId id) {
+ // the prefix is globally unique and the id locally in a namespace
+ // therefore a concatenation of both is also unique
+ String res = NamespacesResource.getPrefix(id.getNamespace()) + "__" + id.getXmlId().getEncoded();
+ return res;
+ }
+
+ public static String getDefinitionsFileName(TOSCAComponentId id) {
+ return CSARExporter.getDefinitionsName(id) + Constants.SUFFIX_TOSCA_DEFINITIONS;
+ }
+
+ public static String getDefinitionsPathInsideCSAR(TOSCAComponentId id) {
+ return CSARExporter.DEFINITONS_PATH_PREFIX + CSARExporter.getDefinitionsFileName(id);
+ }
+
+ /**
+ * Writes a complete CSAR containing all necessary things reachable from the
+ * given service template
+ *
+ * @param id the id of the service template to export
+ * @param out the outputstream to write to
+ * @throws JAXBException
+ */
+ public void writeCSAR(TOSCAComponentId entryId, OutputStream out) throws ArchiveException, IOException, XMLStreamException, JAXBException {
+ CSARExporter.logger.trace("Starting CSAR export with {}", entryId.toString());
+
+ Map<RepositoryFileReference, String> refMap = new HashMap<RepositoryFileReference, String>();
+ Collection<String> definitionNames = new ArrayList<>();
+
+ final ArchiveOutputStream zos = new ArchiveStreamFactory().createArchiveOutputStream("zip", out);
+
+ TOSCAExportUtil exporter = new TOSCAExportUtil();
+ Map<String, Object> conf = new HashMap<>();
+
+ ExportedState exportedState = new ExportedState();
+
+ TOSCAComponentId currentId = entryId;
+ do {
+ String defName = CSARExporter.getDefinitionsPathInsideCSAR(currentId);
+ definitionNames.add(defName);
+
+ zos.putArchiveEntry(new ZipArchiveEntry(defName));
+ Collection<TOSCAComponentId> referencedIds;
+ try {
+ referencedIds = exporter.exportTOSCA(currentId, zos, refMap, conf);
+ } catch (IllegalStateException e) {
+ // thrown if something went wrong inside the repo
+ out.close();
+ // we just rethrow as there currently is no error stream.
+ throw e;
+ }
+ zos.closeArchiveEntry();
+
+ exportedState.flagAsExported(currentId);
+ exportedState.flagAsExportRequired(referencedIds);
+
+ currentId = exportedState.pop();
+ } while (currentId != null);
+
+ // if we export a ServiceTemplate, data for the self-service portal might exist
+ if (entryId instanceof ServiceTemplateId) {
+ this.addSelfServiceMetaData((ServiceTemplateId) entryId, refMap);
+ }
+
+ // now, refMap contains all files to be added to the CSAR
+
+ // write manifest directly after the definitions to have it more at the beginning of the ZIP rather than having it at the very end
+ this.addManifest(entryId, definitionNames, refMap, zos);
+
+ // used for generated XSD schemas
+ TransformerFactory tFactory = TransformerFactory.newInstance();
+ Transformer transformer;
+ try {
+ transformer = tFactory.newTransformer();
+ } catch (TransformerConfigurationException e1) {
+ CSARExporter.logger.debug(e1.getMessage(), e1);
+ throw new IllegalStateException("Could not instantiate transformer", e1);
+ }
+
+ // write all referenced files
+ for (RepositoryFileReference ref : refMap.keySet()) {
+ String archivePath = refMap.get(ref);
+ CSARExporter.logger.trace("Creating {}", archivePath);
+ ArchiveEntry archiveEntry = new ZipArchiveEntry(archivePath);
+ zos.putArchiveEntry(archiveEntry);
+ if (ref instanceof DummyRepositoryFileReferenceForGeneratedXSD) {
+ CSARExporter.logger.trace("Special treatment for generated XSDs");
+ Document document = ((DummyRepositoryFileReferenceForGeneratedXSD) ref).getDocument();
+ DOMSource source = new DOMSource(document);
+ StreamResult result = new StreamResult(zos);
+ try {
+ transformer.transform(source, result);
+ } catch (TransformerException e) {
+ CSARExporter.logger.debug("Could not serialize generated xsd", e);
+ }
+ } else {
+ try (InputStream is = Repository.INSTANCE.newInputStream(ref)) {
+ IOUtils.copy(is, zos);
+ } catch (Exception e) {
+ CSARExporter.logger.error("Could not copy file content to ZIP outputstream", e);
+ }
+ }
+ zos.closeArchiveEntry();
+ }
+
+ this.addNamespacePrefixes(zos);
+
+ zos.finish();
+ zos.close();
+ }
+
+ /**
+ * Writes the configured mapping namespaceprefix -> namespace to the archive
+ *
+ * This is kind of a quick hack. TODO: during the import, the prefixes
+ * should be extracted using JAXB and stored in the NamespacesResource
+ *
+ * @throws IOException
+ */
+ private void addNamespacePrefixes(ArchiveOutputStream zos) throws IOException {
+ Configuration configuration = Repository.INSTANCE.getConfiguration(new NamespacesId());
+ if (configuration instanceof PropertiesConfiguration) {
+ // Quick hack: direct serialization only works for PropertiesConfiguration
+ PropertiesConfiguration pconf = (PropertiesConfiguration) configuration;
+ ArchiveEntry archiveEntry = new ZipArchiveEntry(CSARExporter.PATH_TO_NAMESPACES_PROPERTIES);
+ zos.putArchiveEntry(archiveEntry);
+ try {
+ pconf.save(zos);
+ } catch (ConfigurationException e) {
+ CSARExporter.logger.debug(e.getMessage(), e);
+ zos.write("#Could not export properties".getBytes());
+ zos.write(("#" + e.getMessage()).getBytes());
+ }
+ zos.closeArchiveEntry();
+ }
+ }
+
+ private void addSelfServiceMetaData(ServiceTemplateId entryId, Map<RepositoryFileReference, String> refMap) {
+ SelfServiceMetaDataId id = new SelfServiceMetaDataId(entryId);
+ if (Repository.INSTANCE.exists(id)) {
+ SelfServicePortalResource res = new SelfServicePortalResource(entryId);
+
+ refMap.put(res.data_xml_ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + "data.xml");
+
+ // The schema says that the images have to exist
+ // However, at a quick modeling, there might be no images
+ // Therefore, we check for existence
+ if (Repository.INSTANCE.exists(res.icon_jpg_ref)) {
+ refMap.put(res.icon_jpg_ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + "icon.jpg");
+ }
+ if (Repository.INSTANCE.exists(res.image_jpg_ref)) {
+ refMap.put(res.image_jpg_ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + "image.jpg");
+ }
+
+ Application application = res.getApplication();
+ Options options = application.getOptions();
+ if (options != null) {
+ for (ApplicationOption option : options.getOption()) {
+ String url = option.getIconUrl();
+ if (Util.isRelativeURI(url)) {
+ RepositoryFileReference ref = new RepositoryFileReference(id, url);
+ if (Repository.INSTANCE.exists(ref)) {
+ refMap.put(ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + url);
+ } else {
+ CSARExporter.logger.error("Data corrupt: pointing to non-existent file " + ref);
+ }
+ }
+
+ url = option.getPlanInputMessageUrl();
+ if (Util.isRelativeURI(url)) {
+ RepositoryFileReference ref = new RepositoryFileReference(id, url);
+ if (Repository.INSTANCE.exists(ref)) {
+ refMap.put(ref, Constants.DIRNAME_SELF_SERVICE_METADATA + "/" + url);
+ } else {
+ CSARExporter.logger.error("Data corrupt: pointing to non-existent file " + ref);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void addManifest(TOSCAComponentId id, Collection<String> definitionNames, Map<RepositoryFileReference, String> refMap, ArchiveOutputStream out) throws IOException {
+ String entryDefinitionsReference = CSARExporter.getDefinitionsPathInsideCSAR(id);
+
+ out.putArchiveEntry(new ZipArchiveEntry("TOSCA-Metadata/TOSCA.meta"));
+ PrintWriter pw = new PrintWriter(out);
+ // Setting Versions
+ pw.println("TOSCA-Meta-Version: 1.0");
+ pw.println("CSAR-Version: 1.0");
+ String versionString = "Created-By: Winery " + Prefs.INSTANCE.getVersion();
+ pw.println(versionString);
+ // Winery currently is unaware of tDefinitions, therefore, we use the
+ // name of the service template
+ pw.println("Entry-Definitions: " + entryDefinitionsReference);
+ pw.println();
+
+ assert (definitionNames.contains(entryDefinitionsReference));
+ for (String name : definitionNames) {
+ pw.println("Name: " + name);
+ pw.println("Content-Type: " + org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_TOSCA_DEFINITIONS);
+ pw.println();
+ }
+
+ // Setting other files, mainly files belonging to artifacts
+ for (RepositoryFileReference ref : refMap.keySet()) {
+ String archivePath = refMap.get(ref);
+ pw.println("Name: " + archivePath);
+ String mimeType;
+ if (ref instanceof DummyRepositoryFileReferenceForGeneratedXSD) {
+ mimeType = MimeTypes.MIMETYPE_XSD;
+ } else {
+ mimeType = Repository.INSTANCE.getMimeType(ref);
+ }
+ pw.println("Content-Type: " + mimeType);
+ pw.println();
+ }
+ pw.flush();
+ out.closeArchiveEntry();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java
new file mode 100644
index 0000000..05c7ce1
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyParentForGeneratedXSDRef.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.export;
+
+import org.eclipse.winery.common.ids.GenericId;
+import org.eclipse.winery.common.ids.XMLId;
+
+public class DummyParentForGeneratedXSDRef extends GenericId {
+
+ protected DummyParentForGeneratedXSDRef() {
+ super(new XMLId("dummy", false));
+ }
+
+ @Override
+ public int compareTo(GenericId o) {
+ throw new IllegalStateException("Should never be called.");
+ }
+
+ @Override
+ public GenericId getParent() {
+ throw new IllegalStateException("Should never be called.");
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof DummyParentForGeneratedXSDRef);
+ }
+
+ @Override
+ public int hashCode() {
+ return 0;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java
new file mode 100644
index 0000000..ab8386f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/DummyRepositoryFileReferenceForGeneratedXSD.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.export;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.w3c.dom.Document;
+
+/**
+ * Class used to indicate reference to a generated XSD
+ */
+public class DummyRepositoryFileReferenceForGeneratedXSD extends RepositoryFileReference {
+
+ private final Document document;
+
+
+ /**
+ * @param document the W3C DOM Document holding the generated XSD
+ */
+ public DummyRepositoryFileReferenceForGeneratedXSD(Document document) {
+ // we have to create a unique filename in the case two different XSDs are exported
+ // document.hashCode should be unique enough for us
+ super(new DummyParentForGeneratedXSDRef(), Integer.toString(document.hashCode()));
+ this.document = document;
+ }
+
+ public Document getDocument() {
+ return this.document;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java
new file mode 100644
index 0000000..609d4d6
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/ExportedState.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.export;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Queue;
+
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+
+/**
+ * Holds the state of ids regarding the export <br />
+ *
+ * Required as we do not know at the entry point (usually a service template),
+ * which other components are linked <br />
+ *
+ * Users can call flagAsExportRequired more than once for the same id. If an id
+ * is already exported, it is not flagged as exported again
+ */
+public class ExportedState {
+
+ private final Collection<TOSCAComponentId> exported = new HashSet<>();
+ private final Queue<TOSCAComponentId> exportRequired = new ArrayDeque<>();
+
+
+ /**
+ * @return the first tosca component id to be exported, null if no more
+ * elements are in the queue
+ */
+ public TOSCAComponentId pop() {
+ return this.exportRequired.poll();
+ }
+
+ public void flagAsExported(TOSCAComponentId id) {
+ this.exportRequired.remove(id);
+ this.exported.add(id);
+ }
+
+ /**
+ * Flags the given id as required for export, if not already exported
+ *
+ * @param id the id to flag
+ */
+ public void flagAsExportRequired(TOSCAComponentId id) {
+ if (!this.exported.contains(id)) {
+ this.exportRequired.add(id);
+ }
+ }
+
+ public void flagAsExportRequired(Collection<TOSCAComponentId> ids) {
+ for (TOSCAComponentId id : ids) {
+ if ((!this.exported.contains(id)) && (!this.exportRequired.contains(id))) {
+ this.exportRequired.add(id);
+ }
+ }
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java
new file mode 100644
index 0000000..765b07a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/export/TOSCAExportUtil.java
@@ -0,0 +1,802 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Kálmán Képes - initial API and implementation and/or initial documentation
+ * Oliver Kopp - adapted to new storage model and to TOSCA v1.0
+ *******************************************************************************/
+package org.eclipse.winery.repository.export;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.constants.QNames;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
+import org.eclipse.winery.common.ids.definitions.EntityTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
+import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.RequirementTypeId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId;
+import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.tosca.Definitions;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Policies;
+import org.eclipse.winery.model.tosca.TCapability;
+import org.eclipse.winery.model.tosca.TCapabilityDefinition;
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.model.tosca.TDeploymentArtifacts;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition;
+import org.eclipse.winery.model.tosca.TImplementationArtifact;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts;
+import org.eclipse.winery.model.tosca.TImport;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TNodeTemplate.Capabilities;
+import org.eclipse.winery.model.tosca.TNodeTemplate.Requirements;
+import org.eclipse.winery.model.tosca.TNodeType;
+import org.eclipse.winery.model.tosca.TNodeType.CapabilityDefinitions;
+import org.eclipse.winery.model.tosca.TNodeType.RequirementDefinitions;
+import org.eclipse.winery.model.tosca.TPolicy;
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.model.tosca.TRelationshipType;
+import org.eclipse.winery.model.tosca.TRelationshipType.ValidSource;
+import org.eclipse.winery.model.tosca.TRelationshipType.ValidTarget;
+import org.eclipse.winery.model.tosca.TRequirement;
+import org.eclipse.winery.model.tosca.TRequirementDefinition;
+import org.eclipse.winery.repository.JAXBSupport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.constants.Filename;
+import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource;
+import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplateResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.requirementtypes.RequirementTypeResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+import org.w3c.dom.Document;
+
+public class TOSCAExportUtil {
+
+ private static final XLogger logger = XLoggerFactory.getXLogger(TOSCAExportUtil.class);
+
+ /*
+ * these two are GLOBAL VARIABLES leading to the fact that this class has to
+ * be constructed for each export
+ */
+
+ // collects the references to be put in the CSAR and the assigned path in
+ // the CSAR MANIFEST
+ // this allows to use other paths in the CSAR than on the local storage
+ private Map<RepositoryFileReference, String> referencesToPathInCSARMap = null;
+
+ /**
+ * Currently a very simple approach to configure the export
+ */
+ private Map<String, Object> exportConfiguration;
+
+
+ public enum ExportProperties {
+ INCLUDEXYCOORDINATES, REPOSITORY_URI
+ };
+
+
+ /**
+ * Writes the <em>complete</em> tosca xml into the given outputstream
+ *
+ * @param id the id of the TOSCA component instance to export
+ * @param out outputstream to write to
+ * @param addRelatedComponents true: all referenced components
+ * (artifactTemplates, artifactTypes, ...) are added, false: only
+ * the XML belonging to the id is exported. If XML types are
+ * generated by Winery (e.g., the properties XSD for node types),
+ * these XML types are also exported
+ * @param exportConfiguration the configuration map for the export. Uses
+ * @param exportedState exportedState object to modify. ExportProperties
+ * provides the possible keys
+ * @return a collection of TOSCAcomponentIds referenced by the given
+ * component
+ * @throws JAXBException
+ */
+ public Collection<TOSCAComponentId> exportTOSCA(TOSCAComponentId id, OutputStream out, Map<String, Object> exportConfiguration) throws IOException, JAXBException {
+ this.exportConfiguration = exportConfiguration;
+ this.initializeExport();
+ return this.writeDefinitionsElement(id, out);
+ }
+
+ private void initializeExport() {
+ this.setDefaultExportConfiguration();
+ // quick hack to avoid NPE
+ if (this.referencesToPathInCSARMap == null) {
+ this.referencesToPathInCSARMap = new HashMap<>();
+ }
+ }
+
+ /**
+ * Quick hack to set defaults. Typically, a configuration builder or similar
+ * is used
+ */
+ private void setDefaultExportConfiguration() {
+ this.checkConfig(ExportProperties.INCLUDEXYCOORDINATES, Boolean.FALSE);
+ }
+
+ private void checkConfig(ExportProperties propKey, Boolean bo) {
+ if (!this.exportConfiguration.containsKey(propKey.toString())) {
+ this.exportConfiguration.put(propKey.toString(), bo);
+ }
+ }
+
+ /**
+ * Writes the <em>complete</em> TOSCA XML into the given outputstream.
+ * Additionally, a the artifactMap is filled to enable the CSAR exporter to
+ * create necessary entries in TOSCA-Meta and to add them to the CSAR itself
+ *
+ * @param id the component instance to export
+ * @param out outputstream to write to
+ * @param exportConfiguration Configures the exporter
+ * @param referencesToPathInCSARMap collects the references to export. It is
+ * updated during the export
+ * @return a collection of TOSCAcomponentIds referenced by the given
+ * component
+ * @throws JAXBException
+ */
+ protected Collection<TOSCAComponentId> exportTOSCA(TOSCAComponentId id, OutputStream out, Map<RepositoryFileReference, String> referencesToPathInCSARMap, Map<String, Object> exportConfiguration) throws IOException, JAXBException {
+ this.referencesToPathInCSARMap = referencesToPathInCSARMap;
+ return this.exportTOSCA(id, out, exportConfiguration);
+ }
+
+ /**
+ * Called when the entry resource is definitions backed
+ *
+ * @throws JAXBException
+ */
+ private void writeDefinitionsElement(Definitions entryDefinitions, OutputStream out) throws JAXBException {
+ Marshaller m = JAXBSupport.createMarshaller(true);
+ m.marshal(entryDefinitions, out);
+ }
+
+ /**
+ * Writes the Definitions belonging to the given TOSCA component to the
+ * outputstream
+ *
+ * @return a collection of TOSCAcomponentIds referenced by the given
+ * component
+ *
+ * @throws IOException
+ * @throws JAXBException
+ * @throws IllegalStateException if tcId does not exist
+ */
+ private Collection<TOSCAComponentId> writeDefinitionsElement(TOSCAComponentId tcId, OutputStream out) throws IOException, JAXBException {
+ if (!Repository.INSTANCE.exists(tcId)) {
+ String error = "Component instance " + tcId.toString() + " does not exist.";
+ TOSCAExportUtil.logger.error(error);
+ throw new IllegalStateException(error);
+ }
+
+ AbstractComponentInstanceResource res = AbstractComponentsResource.getComponentInstaceResource(tcId);
+ Definitions entryDefinitions = res.getDefinitions();
+
+ // BEGIN: Definitions modification
+ // the "imports" collection contains the imports of Definitions, not of other definitions
+ // the other definitions are stored in entryDefinitions.getImport()
+ // we modify the internal definitions object directly. It is not written back to the storage. Therefore, we do not need to clone it
+
+ // the imports (pointing to not-definitions (xsd, wsdl, ...)) already have a correct relative URL. (quick hack)
+ URI uri = (URI) this.exportConfiguration.get(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString());
+ if (uri != null) {
+ // we are in the plain-XML mode, the URLs of the imports have to be adjusted
+ for (TImport i : entryDefinitions.getImport()) {
+ String loc = i.getLocation();
+ assert (loc.startsWith("../"));
+ loc = loc.substring(3);
+ loc = uri + loc;
+ // now the location is an absolute URL
+ i.setLocation(loc);
+ }
+ }
+
+ // files of imports have to be added to the CSAR, too
+ for (TImport i : entryDefinitions.getImport()) {
+ String loc = i.getLocation();
+ if (Util.isRelativeURI(loc)) {
+ // locally stored, add to CSAR
+ GenericImportId iid = new GenericImportId(i);
+ String fileName = Util.getLastURIPart(loc);
+ fileName = Util.URLdecode(fileName);
+ RepositoryFileReference ref = new RepositoryFileReference(iid, fileName);
+ this.putRefAsReferencedItemInCSAR(ref);
+ }
+ }
+
+ // adjust imports: add imports of definitions to it
+ Collection<TOSCAComponentId> referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds(tcId);
+ Collection<TImport> imports = new ArrayList<>();
+ for (TOSCAComponentId id : referencedTOSCAComponentIds) {
+ this.addToImports(id, imports);
+ }
+ entryDefinitions.getImport().addAll(imports);
+
+ if (res.getElement() instanceof TEntityType) {
+ // we have an entity type with a possible properties definition
+ EntityTypeResource entityTypeRes = (EntityTypeResource) res;
+ WinerysPropertiesDefinition wpd = ModelUtilities.getWinerysPropertiesDefinition(entityTypeRes.getEntityType());
+ if (wpd != null) {
+ if (wpd.getIsDerivedFromXSD() == null) {
+ // Write WPD only to file if it exists and is NOT derived from an XSD (which may happen during import)
+
+ String wrapperElementNamespace = wpd.getNamespace();
+ String wrapperElementLocalName = wpd.getElementName();
+
+ // BEGIN: add import and put into CSAR
+
+ TImport imp = new TImport();
+ entryDefinitions.getImport().add(imp);
+
+ // fill known import values
+ imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ imp.setNamespace(wrapperElementNamespace);
+ // add "winerysPropertiesDefinition" flag to import tag to support
+ Map<QName, String> otherAttributes = imp.getOtherAttributes();
+ otherAttributes.put(QNames.QNAME_WINERYS_PROPERTIES_DEFINITION_ATTRIBUTE, "true");
+
+ // Determine location
+ String loc = BackendUtils.getImportLocationForWinerysPropertiesDefinitionXSD((EntityTypeId) tcId, uri, wrapperElementLocalName);
+ if (uri == null) {
+ TOSCAExportUtil.logger.trace("CSAR Export mode. Putting XSD into CSAR");
+ // CSAR Export mode
+ // XSD has to be put into the CSAR
+ Document document = ModelUtilities.getWinerysPropertiesDefinitionXSDAsDocument(wpd);
+
+ // loc in import is URLencoded, loc on filesystem isn't
+ String locInCSAR = Util.URLdecode(loc);
+ // furthermore, the path has to start from the root of the CSAR; currently, it starts from Definitions/
+ locInCSAR = locInCSAR.substring(3);
+ TOSCAExportUtil.logger.trace("Location in CSAR: {}", locInCSAR);
+ this.referencesToPathInCSARMap.put(new DummyRepositoryFileReferenceForGeneratedXSD(document), locInCSAR);
+ }
+ imp.setLocation(loc);
+
+ // END: add import and put into CSAR
+
+ // BEGIN: generate TOSCA conforming PropertiesDefinition
+
+ TEntityType entityType = entityTypeRes.getEntityType();
+ PropertiesDefinition propertiesDefinition = new PropertiesDefinition();
+ propertiesDefinition.setType(new QName(wrapperElementNamespace, wrapperElementLocalName));
+ entityType.setPropertiesDefinition(propertiesDefinition);
+
+ // END: generate TOSCA conforming PropertiesDefinition
+ } else {
+ // otherwise WPD exists, but is derived from XSD
+ // we DO NOT have to remove the winery properties definition from the output to allow "debugging" of the CSAR
+ }
+ }
+ }
+
+ // END: Definitions modification
+
+ this.writeDefinitionsElement(entryDefinitions, out);
+
+ return referencedTOSCAComponentIds;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(EntityTypeId id) {
+ return this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id);
+ }
+
+ /**
+ * There is now equivalent id class for
+ * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal,
+ * therefore we take the super type and hope that the caller knows what he
+ * does.
+ */
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(TOSCAComponentId id) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal res = (AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal) AbstractComponentsResource.getComponentInstaceResource(id);
+ String derivedFrom = res.getInheritanceManagement().getDerivedFrom();
+ if (StringUtils.isEmpty(derivedFrom)) {
+ return Collections.emptySet();
+ } else {
+ // Instantiate an id with the same class as the current id
+ TOSCAComponentId parentId;
+ QName qname = QName.valueOf(derivedFrom);
+
+ Constructor<? extends TOSCAComponentId> constructor;
+ try {
+ constructor = id.getClass().getConstructor(QName.class);
+ } catch (NoSuchMethodException | SecurityException e1) {
+ throw new IllegalStateException("Could get constructor to instantiate parent id", e1);
+ }
+ try {
+ parentId = constructor.newInstance(qname);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ throw new IllegalStateException("Could not instantiate id for parent", e);
+ }
+
+ Collection<TOSCAComponentId> result = new ArrayList<>(1);
+ result.add(parentId);
+ return result;
+ }
+ }
+
+ /**
+ * This method is intended to be used by exportTOSCA. However,
+ * org.eclipse.winery.repository.client requires an XML representation of a
+ * component instances without a surrounding definitions element.
+ *
+ * We name this method differently to prevent wrong calling due to
+ * inheritance
+ *
+ * @param definitionsElement the parent XML element
+ */
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(TOSCAComponentId id) {
+ Collection<TOSCAComponentId> referencedTOSCAComponentIds;
+
+ // first of all, handle the concrete elements
+ if (id instanceof ServiceTemplateId) {
+ referencedTOSCAComponentIds = this.prepareForExport((ServiceTemplateId) id);
+ } else if (id instanceof NodeTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((NodeTypeId) id);
+ } else if (id instanceof NodeTypeImplementationId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((NodeTypeImplementationId) id);
+ } else if (id instanceof RelationshipTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RelationshipTypeId) id);
+ } else if (id instanceof RelationshipTypeImplementationId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RelationshipTypeImplementationId) id);
+ } else if (id instanceof RequirementTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((RequirementTypeId) id);
+ } else if (id instanceof CapabilityTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((CapabilityTypeId) id);
+ } else if (id instanceof ArtifactTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((ArtifactTypeId) id);
+ } else if (id instanceof ArtifactTemplateId) {
+ referencedTOSCAComponentIds = this.prepareForExport((ArtifactTemplateId) id);
+ } else if (id instanceof PolicyTypeId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((PolicyTypeId) id);
+ } else if (id instanceof PolicyTemplateId) {
+ referencedTOSCAComponentIds = this.getReferencedTOSCAComponentIds((PolicyTemplateId) id);
+ } else if (id instanceof GenericImportId) {
+ // in case of imports, there are no other ids referenced
+ referencedTOSCAComponentIds = Collections.emptyList();
+ } else {
+ throw new IllegalStateException("Unhandled id class " + id.getClass());
+ }
+
+ // Then, handle the super classes, which support inheritance
+ // Currently, it is EntityType and EntityTypeImplementation only
+ // Since the latter does not exist in the TOSCA MetaModel, we just handle EntityType here
+ if (id instanceof EntityTypeId) {
+ Collection<TOSCAComponentId> additionalRefs = this.getReferencedTOSCAComponentIds((EntityTypeId) id);
+ // the original referenceTOSCAComponentIds could be unmodifiable
+ // we just create a new one...
+ referencedTOSCAComponentIds = new ArrayList<>(referencedTOSCAComponentIds);
+ // ...and add the new reference
+ referencedTOSCAComponentIds.addAll(additionalRefs);
+ }
+
+ return referencedTOSCAComponentIds;
+ }
+
+ /**
+ * Adds the given id as import to the given imports collection
+ */
+ private void addToImports(TOSCAComponentId id, Collection<TImport> imports) {
+ TImport imp = new TImport();
+ imp.setImportType(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE);
+ imp.setNamespace(id.getNamespace().getDecoded());
+ URI uri = (URI) this.exportConfiguration.get(TOSCAExportUtil.ExportProperties.REPOSITORY_URI.toString());
+ if (uri == null) {
+ // self-contained mode
+ // all Definitions are contained in "Definitions" directory, therefore, we provide the filename only
+ // references are resolved relatively from a definitions element (COS01, line 425)
+ String fn = CSARExporter.getDefinitionsFileName(id);
+ fn = Util.URLencode(fn);
+ imp.setLocation(fn);
+ } else {
+ String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(id));
+ path = path + "?definitions";
+ URI absoluteURI = uri.resolve(path);
+ imp.setLocation(absoluteURI.toString());
+ }
+ imports.add(imp);
+
+ // FIXME: Currently the depended elements (such as the artifact templates linked to a node type implementation) are gathered by the corresponding "addXY" method.
+ // Reason: the corresponding TDefinitions element is *not* updated if a related element is added/removed.
+ // That means: The imports are not changed.
+ // The current issue is that TOSCA allows imports of Definitions only and the repository has the concrete elements as main structure
+ // Although during save the import can be updated (by fetching the associated resource and get the definitions of it),
+ // The concrete definitions cannot be determined without
+ // a) having a complete index of all definitions in the repository
+ // b) crawling through the *complete* repository
+ // Possibly the current solution, just lazily adding all dependent elements is the better solution.
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(NodeTypeImplementationId id) {
+ // We have to use a HashSet to ensure that no duplicate ids are added
+ // There may be multiple DAs/IAs referencing the same type
+ Collection<TOSCAComponentId> ids = new HashSet<>();
+
+ NodeTypeImplementationResource res = new NodeTypeImplementationResource(id);
+
+ // DAs
+ TDeploymentArtifacts deploymentArtifacts = res.getNTI().getDeploymentArtifacts();
+ if (deploymentArtifacts != null) {
+ for (TDeploymentArtifact da : deploymentArtifacts.getDeploymentArtifact()) {
+ QName qname;
+ if ((qname = da.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ ids.add(new ArtifactTypeId(da.getArtifactType()));
+ }
+ }
+
+ // IAs
+ TImplementationArtifacts implementationArtifacts = res.getNTI().getImplementationArtifacts();
+ if (implementationArtifacts != null) {
+ for (TImplementationArtifact ia : implementationArtifacts.getImplementationArtifact()) {
+ QName qname;
+ if ((qname = ia.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ ids.add(new ArtifactTypeId(ia.getArtifactType()));
+ }
+ }
+
+ // inheritance
+ ids.addAll(this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id));
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RelationshipTypeImplementationId id) {
+ // We have to use a HashSet to ensure that no duplicate ids are added
+ // There may be multiple IAs referencing the same type
+ Collection<TOSCAComponentId> ids = new HashSet<>();
+
+ RelationshipTypeImplementationResource res = new RelationshipTypeImplementationResource(id);
+
+ // IAs
+ for (TImplementationArtifact ia : res.getRTI().getImplementationArtifacts().getImplementationArtifact()) {
+ QName qname;
+ if ((qname = ia.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ ids.add(new ArtifactTypeId(ia.getArtifactType()));
+ }
+
+ // inheritance
+ ids.addAll(this.getReferencedTOSCAComponentIdOfParentForAnAbstractComponentsWithTypeReferenceResource(id));
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RequirementTypeId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>(1);
+
+ RequirementTypeResource res = new RequirementTypeResource(id);
+ QName requiredCapabilityType = res.getRequirementType().getRequiredCapabilityType();
+ if (requiredCapabilityType != null) {
+ CapabilityTypeId capId = new CapabilityTypeId(requiredCapabilityType);
+ ids.add(capId);
+ }
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(CapabilityTypeId id) {
+ return Collections.emptyList();
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(PolicyTypeId id) {
+ return Collections.emptyList();
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(PolicyTemplateId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+ PolicyTemplateResource res = new PolicyTemplateResource(id);
+ ids.add(new PolicyTypeId(res.getType()));
+ return ids;
+ }
+
+ /**
+ * Synchronizes the plan model references and returns the referenced TOSCA
+ * Component Ids.
+ */
+ private Collection<TOSCAComponentId> prepareForExport(ServiceTemplateId id) {
+ // We have to use a HashSet to ensure that no duplicate ids are added
+ // E.g., there may be multiple relationship templates having the same type
+ Collection<TOSCAComponentId> ids = new HashSet<>();
+ ServiceTemplateResource res = new ServiceTemplateResource(id);
+
+ // ensure that the plans stored locally are the same ones as stored in the definitions
+ res.synchronizeReferences();
+
+ // add all plans as reference in the CSAR
+ // the data model is consistent with the repository
+ // we crawl through the repository to as putRefAsReferencedItemInCSAR expects a repository file reference
+ PlansId plansContainerId = new PlansId(id);
+ SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class);
+ for (PlanId planId : nestedPlans) {
+ SortedSet<RepositoryFileReference> containedFiles = Repository.INSTANCE.getContainedFiles(planId);
+ // even if we currently support only one file in the directory, we just add everything
+ for (RepositoryFileReference ref : containedFiles) {
+ this.putRefAsReferencedItemInCSAR(ref);
+ }
+ }
+
+ // add included things to export queue
+
+ TBoundaryDefinitions boundaryDefs;
+ if ((boundaryDefs = res.getServiceTemplate().getBoundaryDefinitions()) != null) {
+ Policies policies = boundaryDefs.getPolicies();
+ if (policies != null) {
+ for (TPolicy policy : policies.getPolicy()) {
+ PolicyTypeId policyTypeId = new PolicyTypeId(policy.getPolicyType());
+ ids.add(policyTypeId);
+ }
+ }
+
+ // reqs and caps don't have to be exported here as they are references to existing reqs/caps (of nested node templates)
+ }
+
+ if (res.getServiceTemplate().getTopologyTemplate() != null) {
+ for (TEntityTemplate entityTemplate : res.getServiceTemplate().getTopologyTemplate().getNodeTemplateOrRelationshipTemplate()) {
+ QName qname = entityTemplate.getType();
+ if (entityTemplate instanceof TNodeTemplate) {
+ ids.add(new NodeTypeId(qname));
+ TNodeTemplate n = (TNodeTemplate) entityTemplate;
+
+ // crawl through deployment artifacts
+ TDeploymentArtifacts deploymentArtifacts = n.getDeploymentArtifacts();
+ if (deploymentArtifacts != null) {
+ List<TDeploymentArtifact> das = deploymentArtifacts.getDeploymentArtifact();
+ for (TDeploymentArtifact da : das) {
+ ids.add(new ArtifactTypeId(da.getArtifactType()));
+ if ((qname = da.getArtifactRef()) != null) {
+ ids.add(new ArtifactTemplateId(qname));
+ }
+ }
+ }
+
+ // crawl through reqs/caps
+ Requirements requirements = n.getRequirements();
+ if (requirements != null) {
+ for (TRequirement req : requirements.getRequirement()) {
+ QName type = req.getType();
+ RequirementTypeId rtId = new RequirementTypeId(type);
+ ids.add(rtId);
+ }
+ }
+ Capabilities capabilities = n.getCapabilities();
+ if (capabilities != null) {
+ for (TCapability cap : capabilities.getCapability()) {
+ QName type = cap.getType();
+ CapabilityTypeId ctId = new CapabilityTypeId(type);
+ ids.add(ctId);
+ }
+ }
+
+ // crawl through policies
+ org.eclipse.winery.model.tosca.TNodeTemplate.Policies policies = n.getPolicies();
+ if (policies != null) {
+ for (TPolicy pol : policies.getPolicy()) {
+ QName type = pol.getPolicyType();
+ PolicyTypeId ctId = new PolicyTypeId(type);
+ ids.add(ctId);
+ }
+ }
+ } else {
+ assert (entityTemplate instanceof TRelationshipTemplate);
+ ids.add(new RelationshipTypeId(qname));
+ }
+ }
+ }
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(ArtifactTypeId id) {
+ // no recursive crawling needed
+ return Collections.emptyList();
+ }
+
+ /**
+ * Determines the referenced TOSCA Component Ids and also updates the
+ * references in the Artifact Template
+ *
+ * @return a collection of referenced TOCSA Component Ids
+ */
+ private Collection<TOSCAComponentId> prepareForExport(ArtifactTemplateId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+
+ ArtifactTemplateResource res = new ArtifactTemplateResource(id);
+
+ // "Export" type
+ QName type = res.getType();
+ if (type == null) {
+ throw new IllegalStateException("Type is null for " + id.toString());
+ }
+ ids.add(new ArtifactTypeId(type));
+
+ // Export files
+
+ // This method is called BEFORE the concrete definitions element is written.
+ // Therefore, we adapt the content of the attached files to the really existing files
+ res.synchronizeReferences();
+
+ ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(id);
+ SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(fileDir);
+ for (RepositoryFileReference ref : files) {
+ // Even if writing a TOSCA only (!this.writingCSAR),
+ // we put the virtual path in the TOSCA
+ // Reason: Winery is mostly used as a service and local storage
+ // reference to not make sense
+ // The old implementation had absolutePath.toUri().toString();
+ // there, but this does not work when using a cloud blob store.
+
+ this.putRefAsReferencedItemInCSAR(ref);
+ }
+
+ return ids;
+ }
+
+ /**
+ * Puts the given reference as item in the CSAR
+ *
+ * Thereby, it uses the global variable referencesToPathInCSARMap
+ */
+ private void putRefAsReferencedItemInCSAR(RepositoryFileReference ref) {
+ // Determine path
+ String path = BackendUtils.getPathInsideRepo(ref);
+
+ // put mapping reference to path into global map
+ // the path is the same as put in "synchronizeReferences"
+ this.referencesToPathInCSARMap.put(ref, path);
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(RelationshipTypeId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+
+ // add all implementations
+ Collection<RelationshipTypeImplementationId> allTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, id.getQName());
+ for (RelationshipTypeImplementationId ntiId : allTypeImplementations) {
+ ids.add(ntiId);
+ }
+
+ RelationshipTypeResource res = new RelationshipTypeResource(id);
+ TRelationshipType relationshipType = (TRelationshipType) res.getElement();
+
+ ValidSource validSource = relationshipType.getValidSource();
+ if (validSource != null) {
+ QName typeRef = validSource.getTypeRef();
+ // can be a node type or a requirement type
+
+ // similar code as for valid target (difference: req/cap)
+ NodeTypeId ntId = new NodeTypeId(typeRef);
+ if (Repository.INSTANCE.exists(ntId)) {
+ ids.add(ntId);
+ } else {
+ RequirementTypeId rtId = new RequirementTypeId(typeRef);
+ ids.add(rtId);
+ }
+ }
+
+ ValidTarget validTarget = relationshipType.getValidTarget();
+ if (validTarget != null) {
+ QName typeRef = validTarget.getTypeRef();
+ // can be a node type or a capability type
+
+ // similar code as for valid target (difference: req/cap)
+ NodeTypeId ntId = new NodeTypeId(typeRef);
+ if (Repository.INSTANCE.exists(ntId)) {
+ ids.add(ntId);
+ } else {
+ CapabilityTypeId capId = new CapabilityTypeId(typeRef);
+ ids.add(capId);
+ }
+ }
+
+ this.addVisualAppearanceToCSAR(id);
+
+ return ids;
+ }
+
+ private Collection<TOSCAComponentId> getReferencedTOSCAComponentIds(NodeTypeId id) {
+ Collection<TOSCAComponentId> ids = new ArrayList<>();
+ Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, id.getQName());
+ for (NodeTypeImplementationId ntiId : allNodeTypeImplementations) {
+ ids.add(ntiId);
+ }
+
+ NodeTypeResource res = new NodeTypeResource(id);
+ TNodeType nodeType = (TNodeType) res.getElement();
+
+ // add all referenced requirement types
+ RequirementDefinitions reqDefsContainer = nodeType.getRequirementDefinitions();
+ if (reqDefsContainer != null) {
+ List<TRequirementDefinition> reqDefs = reqDefsContainer.getRequirementDefinition();
+ for (TRequirementDefinition reqDef : reqDefs) {
+ RequirementTypeId reqTypeId = new RequirementTypeId(reqDef.getRequirementType());
+ ids.add(reqTypeId);
+ }
+ }
+
+ // add all referenced capability types
+ CapabilityDefinitions capDefsContainer = nodeType.getCapabilityDefinitions();
+ if (capDefsContainer != null) {
+ List<TCapabilityDefinition> capDefs = capDefsContainer.getCapabilityDefinition();
+ for (TCapabilityDefinition capDef : capDefs) {
+ CapabilityTypeId capTypeId = new CapabilityTypeId(capDef.getCapabilityType());
+ ids.add(capTypeId);
+ }
+ }
+
+ this.addVisualAppearanceToCSAR(id);
+
+ return ids;
+ }
+
+ private void addVisualAppearanceToCSAR(TopologyGraphElementEntityTypeId id) {
+ VisualAppearanceId visId = new VisualAppearanceId(id);
+ if (Repository.INSTANCE.exists(visId)) {
+ // we do NOT check for the id, but simply check for bigIcon.png (only exists in NodeType) and smallIcon.png (exists in NodeType and RelationshipType)
+
+ RepositoryFileReference ref = new RepositoryFileReference(visId, Filename.FILENAME_BIG_ICON);
+ if (Repository.INSTANCE.exists(ref)) {
+ this.referencesToPathInCSARMap.put(ref, BackendUtils.getPathInsideRepo(ref));
+ }
+
+ ref = new RepositoryFileReference(visId, Filename.FILENAME_SMALL_ICON);
+ if (Repository.INSTANCE.exists(ref)) {
+ this.referencesToPathInCSARMap.put(ref, BackendUtils.getPathInsideRepo(ref));
+ }
+ }
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java
new file mode 100644
index 0000000..26963a9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/importing/CSARImporter.java
@@ -0,0 +1,1158 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Kálmán Képes - initial API and implementation and/or initial documentation
+ * Oliver Kopp - adapted to new storage model and to TOSCA v1.0
+ *******************************************************************************/
+package org.eclipse.winery.repository.importing;
+
+import static java.nio.file.FileVisitResult.CONTINUE;
+import static java.nio.file.FileVisitResult.SKIP_SUBTREE;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.ws.rs.core.MediaType;
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.io.FilenameUtils;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.constants.MimeTypes;
+import org.eclipse.winery.common.constants.Namespaces;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.EntityTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
+import org.eclipse.winery.common.ids.definitions.imports.XSDImportId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.csar.toscametafile.TOSCAMetaFile;
+import org.eclipse.winery.model.csar.toscametafile.TOSCAMetaFileParser;
+import org.eclipse.winery.model.tosca.Definitions;
+import org.eclipse.winery.model.tosca.TArtifactReference;
+import org.eclipse.winery.model.tosca.TArtifactReference.Exclude;
+import org.eclipse.winery.model.tosca.TArtifactReference.Include;
+import org.eclipse.winery.model.tosca.TArtifactTemplate;
+import org.eclipse.winery.model.tosca.TArtifactTemplate.ArtifactReferences;
+import org.eclipse.winery.model.tosca.TDefinitions;
+import org.eclipse.winery.model.tosca.TDefinitions.Types;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImport;
+import org.eclipse.winery.model.tosca.TNodeType;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
+import org.eclipse.winery.model.tosca.TPlans;
+import org.eclipse.winery.model.tosca.TRelationshipType;
+import org.eclipse.winery.model.tosca.TServiceTemplate;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.JAXBSupport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.constants.Filename;
+import org.eclipse.winery.repository.backend.filebased.FileUtils;
+import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
+import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.export.CSARExporter;
+import org.eclipse.winery.repository.resources.admin.NamespacesResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Element;
+
+/**
+ * Imports a CSAR into the storage. As the internal storage format does not have
+ * CSARs as the topmost artifacts, but one TDefinition, the CSAR has to be split
+ * up into several components.
+ *
+ * Existing components are <em>not</em> replaced, but silently skipped
+ *
+ * Minor errors are logged and not further propagated / notified. That means, a
+ * user cannot see minor errors. Major errors are immediately thrown.
+ *
+ * One instance for each import
+ */
+public class CSARImporter {
+
+ private static final Logger logger = LoggerFactory.getLogger(CSARImporter.class);
+
+ // ExecutorService for XSD schema initialization
+ // Threads set to 1 to avoid testing for parallel processing of the same XSD file
+ private static final ExecutorService xsdParsingService = Executors.newFixedThreadPool(1);
+
+ private static final ExecutorService entityTypeAdjestmentService = Executors.newFixedThreadPool(10);
+
+
+ /**
+ * Reads the CSAR from the given inputstream
+ *
+ * @param in the inputstream to read from
+ * @param errorList the list of errors during the import. Has to be non-null
+ * @param overwrite if true: contents of the repo are overwritten
+ *
+ * @throws InvalidCSARException if the CSAR is invalid
+ */
+ public void readCSAR(InputStream in, List<String> errors, boolean overwrite, final boolean asyncWPDParsing) throws IOException {
+ // we have to extract the file to a temporary directory as
+ // the .definitions file does not necessarily have to be the first entry in the archive
+ Path csarDir = Files.createTempDirectory("winery");
+
+ try (ZipInputStream zis = new ZipInputStream(in)) {
+ ZipEntry entry;
+ while ((entry = zis.getNextEntry()) != null) {
+ if (!entry.isDirectory()) {
+ Path targetPath = csarDir.resolve(entry.getName());
+ Files.createDirectories(targetPath.getParent());
+ Files.copy(zis, targetPath);
+ }
+ }
+ this.importFromDir(csarDir, errors, overwrite, asyncWPDParsing);
+ } catch (Exception e) {
+ CSARImporter.logger.debug("Could not import CSAR", e);
+ throw e;
+ } finally {
+ // cleanup: delete all contents of the temporary directory
+ FileUtils.forceDelete(csarDir);
+ }
+ }
+
+ /**
+ * Import an extracted CSAR from a directory
+ *
+ * @param path the root path of an extracted CSAR file
+ * @param overwrite if true: contents of the repo are overwritten
+ * @param asyncWPDParsing true if WPD should be parsed asynchronously to
+ * speed up the import. Required, because JUnit terminates the
+ * used ExecutorService
+ * @throws InvalidCSARException
+ * @throws IOException
+ */
+ void importFromDir(final Path path, final List<String> errors, final boolean overwrite, final boolean asyncWPDParsing) throws IOException {
+ Path toscaMetaPath = path.resolve("TOSCA-Metadata/TOSCA.meta");
+ if (!Files.exists(toscaMetaPath)) {
+ errors.add("TOSCA.meta does not exist");
+ return;
+ }
+ final TOSCAMetaFileParser tmfp = new TOSCAMetaFileParser();
+ final TOSCAMetaFile tmf = tmfp.parse(toscaMetaPath);
+
+ // we do NOT do any sanity checks, of TOSAC.meta
+ // and just start parsing
+
+ if (tmf.getEntryDefinitions() != null) {
+ // we obey the entry definitions and "just" import that
+ // imported definitions are added recursively
+ Path defsPath = path.resolve(tmf.getEntryDefinitions());
+ this.importDefinitions(tmf, defsPath, errors, overwrite, asyncWPDParsing);
+
+ this.importSelfServiceMetaData(tmf, path, defsPath, errors);
+ } else {
+ // no explicit entry definitions found
+ // we import all available definitions
+ // The specification says (cos01, Section 16.1, line 2935) that all definitions are contained in the "Definitions" directory
+ // The alternative is to go through all entries in the TOSCA Meta File, but there is no guarantee that this list is complete
+ Path definitionsDir = path.resolve("Definitions");
+ if (!Files.exists(definitionsDir)) {
+ errors.add("No entry definitions defined and Definitions directory does not exist.");
+ return;
+ }
+ final List<IOException> exceptions = new ArrayList<IOException>();
+ Files.walkFileTree(definitionsDir, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ if (dir.endsWith("Definitions")) {
+ return FileVisitResult.CONTINUE;
+ } else {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ try {
+ CSARImporter.this.importDefinitions(tmf, file, errors, overwrite, asyncWPDParsing);
+ } catch (IOException e) {
+ exceptions.add(e);
+ return FileVisitResult.TERMINATE;
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ if (!exceptions.isEmpty()) {
+ // something went wrong during parsing
+ // we rethrow the exception
+ throw exceptions.get(0);
+ }
+ }
+
+ this.importNamespacePrefixes(path);
+ }
+
+
+ private static final Pattern GENERATED_PREFIX_PATTERN = Pattern.compile("^ns\\d+$");
+
+
+ /**
+ * Import namespace prefixes. This is kind of a quick hack. TODO: during the
+ * import, the prefixes should be extracted using JAXB and stored in the
+ * NamespacesResource
+ *
+ * @param rootPath the root path of the extracted CSAR
+ */
+ private void importNamespacePrefixes(Path rootPath) {
+ Path properties = rootPath.resolve(CSARExporter.PATH_TO_NAMESPACES_PROPERTIES);
+ if (Files.exists(properties)) {
+ PropertiesConfiguration pconf;
+ try {
+ pconf = new PropertiesConfiguration(properties.toFile());
+ } catch (ConfigurationException e) {
+ CSARImporter.logger.debug(e.getMessage(), e);
+ return;
+ }
+ Iterator<String> namespaces = pconf.getKeys();
+ while (namespaces.hasNext()) {
+ boolean addToStorage = false;
+ String namespace = namespaces.next();
+ if (NamespacesResource.INSTANCE.getIsPrefixKnownForNamespace(namespace)) {
+ String storedPrefix = NamespacesResource.getPrefix(namespace);
+ // QUICK HACK to check whether the prefix is a generated one
+ // We assume we know the internal generation routine
+ Matcher m = CSARImporter.GENERATED_PREFIX_PATTERN.matcher(storedPrefix);
+ if (m.matches()) {
+ // the stored prefix is a generated one
+ // replace it by the one stored in the exported properties
+ addToStorage = true;
+ }
+ } else {
+ addToStorage = true;
+ }
+ if (addToStorage) {
+ String prefix = pconf.getString(namespace);
+ NamespacesResource.INSTANCE.addNamespace(namespace, prefix);
+ }
+ }
+ }
+ }
+
+ /**
+ * Imports a self-service meta data description (if available)
+ *
+ * The first service template in the provided entry definitions is taken
+ *
+ * @param tmf
+ *
+ * @param errors
+ */
+ private void importSelfServiceMetaData(final TOSCAMetaFile tmf, final Path rootPath, Path entryDefinitions, final List<String> errors) {
+ final Path selfServiceDir = rootPath.resolve(Constants.DIRNAME_SELF_SERVICE_METADATA);
+ if (!Files.exists(selfServiceDir)) {
+ CSARImporter.logger.debug("Self-service Portal directory does not exist in CSAR");
+ return;
+ }
+ if (!Files.exists(entryDefinitions)) {
+ CSARImporter.logger.debug("Entry definitions does not exist.");
+ return;
+ }
+
+ Unmarshaller um = JAXBSupport.createUnmarshaller();
+ TDefinitions defs;
+ try {
+ defs = (TDefinitions) um.unmarshal(entryDefinitions.toFile());
+ } catch (JAXBException e) {
+ errors.add("Could not unmarshal definitions " + entryDefinitions.getFileName() + " " + e.getMessage());
+ return;
+ } catch (ClassCastException e) {
+ errors.add("Definitions " + entryDefinitions.getFileName() + " is not a TDefinitions " + e.getMessage());
+ return;
+ }
+
+ final int cutLength = selfServiceDir.toString().length() + 1;
+ Iterator<TExtensibleElements> iterator = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().iterator();
+ boolean found = false;
+ TExtensibleElements next = null;
+ while (iterator.hasNext() && !found) {
+ next = iterator.next();
+ if (next instanceof TServiceTemplate) {
+ found = true;
+ }
+ }
+
+ if (found) {
+ TServiceTemplate serviceTemplate = (TServiceTemplate) next;
+ String namespace = serviceTemplate.getTargetNamespace();
+ if (namespace == null) {
+ namespace = defs.getTargetNamespace();
+ }
+ ServiceTemplateId stId = new ServiceTemplateId(namespace, serviceTemplate.getId(), false);
+ final SelfServiceMetaDataId id = new SelfServiceMetaDataId(stId);
+
+ // QUICK HACK: We just import all data without any validation
+ // Reason: the metadata resource can deal with nearly arbitrary formats of the data, therefore we do not do any checking here
+
+ try {
+ Files.walkFileTree(selfServiceDir, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ String name = file.toString().substring(cutLength);
+ // check: if name contains "/", this could lead to exceptions
+ RepositoryFileReference ref = new RepositoryFileReference(id, name);
+
+ if (name.equals("data.xml")) {
+ // we have to check whether the data.xml contains
+ // (uri:"http://opentosca.org/self-service", local:"application")
+ // instead of
+ // (uri:"http://www.eclipse.org/winery/model/selfservice", local:"Application"
+ // We quickly replace it via String replacement instead of XSLT
+ try {
+ String oldContent = org.apache.commons.io.FileUtils.readFileToString(file.toFile(), "UTF-8");
+ String newContent = oldContent.replace("http://opentosca.org/self-service", "http://www.eclipse.org/winery/model/selfservice");
+ newContent = newContent.replace(":application", ":Application");
+ if (!oldContent.equals(newContent)) {
+ // we replaced something -> write new content to old file
+ org.apache.commons.io.FileUtils.writeStringToFile(file.toFile(), newContent, "UTF-8");
+ }
+ } catch (IOException e) {
+ CSARImporter.logger.debug("Could not replace content in data.xml", e);
+ }
+ }
+ CSARImporter.this.importFile(file, ref, tmf, rootPath, errors);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ } catch (IOException e) {
+ CSARImporter.logger.debug(e.getMessage(), e);
+ errors.add("Self-service Meta Data: " + e.getMessage());
+ }
+ }
+
+ }
+
+ /**
+ * Recursively imports the given definitions
+ *
+ * @param tmf the TOSCAMetaFile object holding the parsed content of a TOSCA
+ * meta file. If null, no files must be referenced from the given
+ * definitions
+ * @param overwrite true: existing contents are overwritten
+ * @param asyncWPDParsing
+ * @param definitions the path to the definitions to import
+ *
+ * @throws IOException
+ */
+ public void importDefinitions(TOSCAMetaFile tmf, Path defsPath, final List<String> errors, boolean overwrite, boolean asyncWPDParsing) throws IOException {
+ if (defsPath == null) {
+ throw new IllegalStateException("path to definitions must not be null");
+ }
+ if (!Files.exists(defsPath)) {
+ errors.add(String.format("Definitions %1$s does not exist", defsPath.getFileName()));
+ return;
+ }
+
+ Unmarshaller um = JAXBSupport.createUnmarshaller();
+ TDefinitions defs;
+ try {
+ defs = (TDefinitions) um.unmarshal(defsPath.toFile());
+ } catch (JAXBException e) {
+ Throwable cause = e;
+ String eMsg = "";
+ do {
+ String msg = cause.getMessage();
+ if (msg != null) {
+ eMsg = eMsg + msg + "; ";
+ }
+ cause = cause.getCause();
+ } while (cause != null);
+ errors.add("Could not unmarshal definitions " + defsPath.getFileName() + " " + eMsg);
+ CSARImporter.logger.debug("Unmarshalling error", e);
+ return;
+ } catch (ClassCastException e) {
+ errors.add("Definitions " + defsPath.getFileName() + " is not a TDefinitions " + e.getMessage());
+ return;
+ }
+
+ List<TImport> imports = defs.getImport();
+ this.importImports(defsPath.getParent(), tmf, imports, errors, overwrite, asyncWPDParsing);
+ // imports has been modified to contain necessary imports only
+
+ // this method adds new imports to defs which may not be imported using "importImports".
+ // Therefore, "importTypes" has to be called *after* importImports
+ this.importTypes(defs, errors);
+
+ String defaultNamespace = defs.getTargetNamespace();
+ List<TExtensibleElements> componentInstanceList = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation();
+ for (final TExtensibleElements ci : componentInstanceList) {
+ // Determine namespace
+ String namespace = this.getNamespace(ci, defaultNamespace);
+ // Ensure that element has the namespace
+ this.setNamespace(ci, namespace);
+
+ // Determine id
+ String id = ModelUtilities.getId(ci);
+
+ // Determine WineryId
+ Class<? extends TOSCAComponentId> widClass = org.eclipse.winery.repository.Utils.getComponentIdClassForTExtensibleElements(ci.getClass());
+ final TOSCAComponentId wid = BackendUtils.getTOSCAcomponentId(widClass, namespace, id, false);
+
+ if (Repository.INSTANCE.exists(wid)) {
+ if (overwrite) {
+ Repository.INSTANCE.forceDelete(wid);
+ String msg = String.format("Deleted %1$s %2$s to enable replacement", ci.getClass().getName(), wid.getQName().toString());
+ CSARImporter.logger.debug(msg);
+ } else {
+ String msg = String.format("Skipped %1$s %2$s, because it already exists", ci.getClass().getName(), wid.getQName().toString());
+ CSARImporter.logger.debug(msg);
+ // this is not displayed in the UI as we currently do not distinguish between pre-existing types and types created during the import.
+ continue;
+ }
+ }
+
+ // Create a fresh definitions object without the other data.
+ final Definitions newDefs = BackendUtils.createWrapperDefinitions(wid);
+
+ // copy over the inputs determined by this.importImports
+ newDefs.getImport().addAll(imports);
+
+ // add the current TExtensibleElements as the only content to it
+ newDefs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(ci);
+
+ if (ci instanceof TArtifactTemplate) {
+ // convention: Definitions are stored in the "Definitions" directory, therefore going to levels up (Definitions dir -> root dir) resolves to the root dir
+ // COS01, line 2663 states that the path has to be resolved from the *root* of the CSAR
+ this.adjustArtifactTemplate(defsPath.getParent().getParent(), tmf, (ArtifactTemplateId) wid, (TArtifactTemplate) ci, errors);
+ } else if (ci instanceof TNodeType) {
+ this.adjustNodeType(defsPath.getParent().getParent(), (TNodeType) ci, (NodeTypeId) wid, tmf, errors);
+ } else if (ci instanceof TRelationshipType) {
+ this.adjustRelationshipType(defsPath.getParent().getParent(), (TRelationshipType) ci, (RelationshipTypeId) wid, tmf, errors);
+ } else if (ci instanceof TServiceTemplate) {
+ this.adjustServiceTemplate(defsPath.getParent().getParent(), tmf, (ServiceTemplateId) wid, (TServiceTemplate) ci, errors);
+ }
+
+ // node types and relationship types are subclasses of TEntityType
+ // Therefore, we check the entity type separately here
+ if (ci instanceof TEntityType) {
+ if (asyncWPDParsing) {
+ // Adjusting takes a long time
+ // Therefore, we first save the type as is and convert to Winery-Property-Definitions in the background
+ CSARImporter.storeDefinitions(wid, newDefs);
+ CSARImporter.entityTypeAdjestmentService.submit(new Runnable() {
+
+ @Override
+ public void run() {
+ CSARImporter.adjustEntityType((TEntityType) ci, (EntityTypeId) wid, newDefs, errors);
+ CSARImporter.storeDefinitions(wid, newDefs);
+ }
+ });
+ } else {
+ CSARImporter.adjustEntityType((TEntityType) ci, (EntityTypeId) wid, newDefs, errors);
+ CSARImporter.storeDefinitions(wid, newDefs);
+ }
+ } else {
+ CSARImporter.storeDefinitions(wid, newDefs);
+ }
+ }
+ }
+
+ /**
+ * Imports the specified types into the repository. The types are converted
+ * to an import statement
+ *
+ * @param errors Container for error messages
+ */
+ private void importTypes(TDefinitions defs, final List<String> errors) {
+ Types typesContainer = defs.getTypes();
+ if (typesContainer != null) {
+ List<Object> types = typesContainer.getAny();
+ for (Object type : types) {
+ if (type instanceof Element) {
+ Element element = (Element) type;
+
+ // generate id part of ImportId out of definitions' id
+ // we do not use the name as the name has to be URLencoded again and we have issues with the interplay with org.eclipse.winery.common.ids.definitions.imports.GenericImportId.getId(TImport) then.
+ String id = defs.getId();
+ // try to make the id unique by hashing the "content" of the definition
+ id = id + "-" + Integer.toHexString(element.hashCode());
+
+ // set importId
+ TOSCAComponentId importId;
+ String ns;
+ if (element.getNamespaceURI().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
+ ns = element.getAttribute("targetNamespace");
+ importId = new XSDImportId(ns, id, false);
+ } else {
+ // Quick hack for non-XML-Schema-definitions
+ ns = "unknown";
+ importId = new GenericImportId(ns, id, false, element.getNamespaceURI());
+ }
+
+ // Following code is adapted from importOtherImports
+
+ TDefinitions wrapperDefs = BackendUtils.createWrapperDefinitions(importId);
+ TImport imp = new TImport();
+ String fileName = id + ".xsd";
+ imp.setLocation(fileName);
+ imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ imp.setNamespace(ns);
+ wrapperDefs.getImport().add(imp);
+ CSARImporter.storeDefinitions(importId, wrapperDefs);
+
+ // put the file itself to the repo
+ // ref is required to generate fileRef
+ RepositoryFileReference ref = BackendUtils.getRefOfDefinitions(importId);
+ RepositoryFileReference fileRef = new RepositoryFileReference(ref.getParent(), fileName);
+ // convert element to document
+ // QUICK HACK. Alternative: Add new method Repository.INSTANCE.getOutputStream and transform DOM node to OuptputStream
+ String content = Util.getXMLAsString(element);
+ try {
+ Repository.INSTANCE.putContentToFile(fileRef, content, MediaType.APPLICATION_XML_TYPE);
+ } catch (IOException e) {
+ CSARImporter.logger.debug("Could not put XML Schema definition to file " + fileRef.toString(), e);
+ errors.add("Could not put XML Schema definition to file " + fileRef.toString());
+ }
+
+ // add import to definitions
+
+ // adapt path - similar to importOtherImport
+ String newLoc = "../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(fileRef));
+ imp.setLocation(newLoc);
+ defs.getImport().add(imp);
+ } else {
+ // This is a known type. Otherwise JAX-B would render it as Element
+ errors.add("There is a Type of class " + type.getClass().toString() + " which is unknown to Winery. The type element is imported as is");
+ }
+ }
+ }
+ }
+
+ /**
+ * All EntityTypes may contain properties definition. In case a winery
+ * properties definition is found, the TOSCA conforming properties
+ * definition is removed
+ *
+ * @param ci the entity type
+ * @param wid the Winery id of the entitytype
+ * @param newDefs the definitions, the entiy type is contained in. The
+ * imports might be adjusted here
+ * @param errors
+ */
+ private static void adjustEntityType(TEntityType ci, EntityTypeId wid, Definitions newDefs, final List<String> errors) {
+ PropertiesDefinition propertiesDefinition = ci.getPropertiesDefinition();
+ if (propertiesDefinition != null) {
+ WinerysPropertiesDefinition winerysPropertiesDefinition = ModelUtilities.getWinerysPropertiesDefinition(ci);
+ boolean deriveWPD;
+ if (winerysPropertiesDefinition == null) {
+ deriveWPD = true;
+ } else {
+ if (winerysPropertiesDefinition.getIsDerivedFromXSD() == null) {
+ // if the winery's properties are defined by Winery itself,
+ // remove the TOSCA conforming properties definition as a Winery properties definition exists (and which takes precedence)
+ ci.setPropertiesDefinition(null);
+
+ // no derivation from properties required as the properties are generated by Winery
+ deriveWPD = false;
+
+ // we have to remove the import, too
+ // Determine the location
+ String elementName = winerysPropertiesDefinition.getElementName();
+ String loc = BackendUtils.getImportLocationForWinerysPropertiesDefinitionXSD(wid, null, elementName);
+ // remove the import matching that location
+ List<TImport> imports = newDefs.getImport();
+ boolean found = false;
+ if (imports != null) {
+ Iterator<TImport> iterator = imports.iterator();
+ TImport imp;
+ while (iterator.hasNext()) {
+ imp = iterator.next();
+ // TODO: add check for QNames.QNAME_WINERYS_PROPERTIES_DEFINITION_ATTRIBUTE instead of import location. The current routine, however, works, too.
+ if (imp.getLocation().equals(loc)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ // imp with Winery's k/v location found
+ iterator.remove();
+ // the XSD has been imported in importOtherImport
+ // it was too difficult to do the location check there, therefore we just remove the XSD from the repository here
+ XSDImportId importId = new XSDImportId(winerysPropertiesDefinition.getNamespace(), elementName, false);
+ try {
+ Repository.INSTANCE.forceDelete(importId);
+ } catch (IOException e) {
+ CSARImporter.logger.debug("Could not delete Winery's generated XSD definition", e);
+ errors.add("Could not delete Winery's generated XSD definition");
+ }
+ } else {
+ // K/V properties definition was incomplete
+ }
+ }
+ } else {
+ // winery's properties are derived from an XSD
+ // The export does NOT add an imports statement: only the wpd exists
+ // We remove that as
+ ModelUtilities.removeWinerysPropertiesDefinition(ci);
+ // derive the WPDs again from the properties definition
+ deriveWPD = true;
+ }
+ }
+ if (deriveWPD) {
+ BackendUtils.deriveWPD(ci, errors);
+ }
+ }
+ }
+
+ /**
+ * In case plans are provided, the plans are imported into Winery's storage
+ *
+ * @param rootPath the root path of the extracted csar
+ * @param tmf the TOSCAMetaFile object used to determine the mime type of
+ * the plan
+ * @param wid Winery's internal id of the service template
+ * @param st the the service template to be imported {@inheritDoc}
+ *
+ * @throws InvalidCSARException
+ */
+ private void adjustServiceTemplate(Path rootPath, TOSCAMetaFile tmf, ServiceTemplateId wid, TServiceTemplate st, final List<String> errors) {
+ TPlans plans = st.getPlans();
+ if (plans != null) {
+ for (TPlan plan : plans.getPlan()) {
+ PlanModelReference refContainer = plan.getPlanModelReference();
+ if (refContainer != null) {
+ String ref = refContainer.getReference();
+ if (ref != null) {
+ // URLs are stored encoded -> undo the encoding
+ ref = Util.URLdecode(ref);
+ URI refURI;
+ try {
+ refURI = new URI(ref);
+ } catch (URISyntaxException e) {
+ errors.add(String.format("Invalid URI %1$s", ref));
+ continue;
+ }
+ if (refURI.isAbsolute()) {
+ // Points to somewhere external
+ // This is a linked plan
+ // We have to do nothing
+ continue;
+ }
+ Path path = rootPath.resolve(ref);
+ if (!Files.exists(path)) {
+ // possibly, the reference is relative to the Definitions subfolder
+ // COS01 does not make any explicit statement how to resolve the reference here
+ path = rootPath.resolve("Definitions").resolve(ref);
+ if (!Files.exists(path)) {
+ errors.add(String.format("Plan reference %1$s not found", ref));
+ // we quickly remove the reference to reflect the not-found in the data
+ refContainer.setReference(null);
+ continue;
+ }
+ }
+ PlansId plansId = new PlansId(wid);
+ PlanId pid = new PlanId(plansId, new XMLId(plan.getId(), false));
+ if (Files.isDirectory(path)) {
+ errors.add(String.format("Reference %1$s is a directory and Winery currently does not support importing directories", ref));
+ continue;
+ }
+ RepositoryFileReference fref = new RepositoryFileReference(pid, path.getFileName().toString());
+ this.importFile(path, fref, tmf, rootPath, errors);
+
+ // file is imported
+ // Adjust the reference
+ refContainer.setReference("../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(fref)));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a color to the given relationship type
+ */
+ private void adjustRelationshipType(Path rootPath, TRelationshipType ci, RelationshipTypeId wid, TOSCAMetaFile tmf, final List<String> errors) {
+ VisualAppearanceId visId = new VisualAppearanceId(wid);
+ this.importIcons(rootPath, visId, tmf, errors);
+ }
+
+ private void adjustNodeType(Path rootPath, TNodeType ci, NodeTypeId wid, TOSCAMetaFile tmf, final List<String> errors) {
+ VisualAppearanceId visId = new VisualAppearanceId(wid);
+ this.importIcons(rootPath, visId, tmf, errors);
+ }
+
+ private void importIcons(Path rootPath, VisualAppearanceId visId, TOSCAMetaFile tmf, final List<String> errors) {
+ String pathInsideRepo = BackendUtils.getPathInsideRepo(visId);
+ Path visPath = rootPath.resolve(pathInsideRepo);
+ this.importIcon(visId, visPath, Filename.FILENAME_BIG_ICON, tmf, rootPath, errors);
+ }
+
+ private void importIcon(VisualAppearanceId visId, Path visPath, String fileName, TOSCAMetaFile tmf, Path rootPath, final List<String> errors) {
+ Path file = visPath.resolve(fileName);
+ if (Files.exists(file)) {
+ RepositoryFileReference ref = new RepositoryFileReference(visId, fileName);
+ this.importFile(file, ref, tmf, rootPath, errors);
+ }
+ }
+
+ /**
+ * Adjusts the given artifact template to conform with the repository format
+ *
+ * We import the files given at the artifact references
+ *
+ * @throws InvalidCSARException
+ * @throws IOException
+ */
+ private void adjustArtifactTemplate(Path rootPath, TOSCAMetaFile tmf, ArtifactTemplateId atid, TArtifactTemplate ci, final List<String> errors) throws IOException {
+ ArtifactReferences refs = ci.getArtifactReferences();
+ if (refs == null) {
+ // no references stored - break
+ return;
+ }
+ List<TArtifactReference> refList = refs.getArtifactReference();
+ Iterator<TArtifactReference> iterator = refList.iterator();
+ while (iterator.hasNext()) {
+ TArtifactReference ref = iterator.next();
+ String reference = ref.getReference();
+ // URLs are stored encoded -> undo the encoding
+ reference = Util.URLdecode(reference);
+
+ URI refURI;
+ try {
+ refURI = new URI(reference);
+ } catch (URISyntaxException e) {
+ errors.add(String.format("Invalid URI %1$s", ref));
+ continue;
+ }
+ if (refURI.isAbsolute()) {
+ // Points to somewhere external
+ // We have to do nothing
+ continue;
+ }
+
+ // we remove the current element as it will be handled during the export
+ iterator.remove();
+
+ Path path = rootPath.resolve(reference);
+ if (!Files.exists(path)) {
+ errors.add(String.format("Reference %1$s not found", reference));
+ return;
+ }
+ Set<Path> allFiles;
+ if (Files.isRegularFile(path)) {
+ allFiles = new HashSet<Path>();
+ allFiles.add(path);
+ } else {
+ assert (Files.isDirectory(path));
+ Path localRoot = rootPath.resolve(path);
+ List<Object> includeOrExclude = ref.getIncludeOrExclude();
+
+ if (includeOrExclude.get(0) instanceof TArtifactReference.Exclude) {
+ // Implicit semantics of an exclude listed first:
+ // include all files and then exclude the files matched by the pattern
+ allFiles = this.getAllFiles(localRoot);
+ } else {
+ // semantics if include lited as first:
+ // same as listed at other places
+ allFiles = new HashSet<>();
+ }
+
+ for (Object object : includeOrExclude) {
+ if (object instanceof TArtifactReference.Include) {
+ this.handleInclude((TArtifactReference.Include) object, localRoot, allFiles);
+ } else {
+ assert (object instanceof TArtifactReference.Exclude);
+ this.handleExclude((TArtifactReference.Exclude) object, localRoot, allFiles);
+ }
+ }
+ }
+ this.importAllFiles(allFiles, atid, tmf, rootPath, errors);
+ }
+
+ if (refList.isEmpty()) {
+ // everything is imported and is a file stored locally
+ // we don't need the references stored locally: they are generated on the fly when exporting
+ ci.setArtifactReferences(null);
+ }
+ }
+
+ /**
+ * Imports a file from the filesystem to the repository
+ *
+ * @param p the file to read from
+ * @param fref the "file" to put the content to
+ * @param tmf the TOSCAMetaFile object used to determine the mimetype. Must
+ * not be null.
+ * @param rootPath used to relativize p to determine the mime type
+ * @throws InvalidCSARException
+ */
+ private void importFile(Path p, RepositoryFileReference fref, TOSCAMetaFile tmf, Path rootPath, final List<String> errors) {
+ if (tmf == null) {
+ throw new IllegalStateException("tmf must not be null");
+ }
+ try (InputStream is = Files.newInputStream(p);
+ BufferedInputStream bis = new BufferedInputStream(is)) {
+ String mediaType = tmf.getMimeType(p.relativize(rootPath).toString());
+ if (mediaType == null) {
+ // Manually find out mime type
+ try {
+ mediaType = Utils.getMimeType(bis, p.getFileName().toString());
+ } catch (IOException e) {
+ errors.add(String.format("No MimeType given for %1$s (%2$s)", p.getFileName(), e.getMessage()));
+ return;
+ }
+ if (mediaType == null) {
+ errors.add(String.format("No MimeType given for %1$s", p.getFileName()));
+ return;
+ }
+ }
+ try {
+ Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType));
+ } catch (IllegalArgumentException | IOException e) {
+ throw new IllegalStateException(e);
+ }
+ } catch (IOException e1) {
+ throw new IllegalStateException("Could not work on generated temporary files", e1);
+ }
+ }
+
+ private void importAllFiles(Collection<Path> allFiles, ArtifactTemplateId atid, TOSCAMetaFile tmf, Path rootPath, final List<String> errors) {
+ // import all files to repository
+ ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(atid);
+ for (Path p : allFiles) {
+ if (!Files.exists(p)) {
+ errors.add(String.format("File %1$s does not exist", p.toString()));
+ return;
+ }
+ RepositoryFileReference fref = new RepositoryFileReference(fileDir, p.getFileName().toString());
+ this.importFile(p, fref, tmf, rootPath, errors);
+ }
+
+ }
+
+ /**
+ * Modifies given allFiles object to exclude all files given by the excl
+ * pattern
+ *
+ * Semantics: Remove all files from the set, which match the given pattern
+ */
+ private void handleExclude(Exclude excl, Path localRoot, Set<Path> allFiles) {
+ PathMatcher pathMatcher = localRoot.getFileSystem().getPathMatcher("glob:" + excl.getPattern());
+ Iterator<Path> it = allFiles.iterator();
+ while (it.hasNext()) {
+ Path curPath = it.next();
+ if (pathMatcher.matches(curPath)) {
+ it.remove();
+ }
+ }
+ }
+
+ /**
+ * Modifies given allFiles object to include all files given by the incl
+ * pattern
+ *
+ * Semantics: Add all files from localRoot to allFiles matching the pattern
+ */
+ private void handleInclude(final Include incl, final Path localRoot, final Set<Path> allFiles) {
+ final PathMatcher pathMatcher = localRoot.getFileSystem().getPathMatcher("glob:" + incl.getPattern());
+ try {
+ Files.walkFileTree(localRoot, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ Path relFile = localRoot.relativize(file);
+ if (pathMatcher.matches(relFile)) {
+ allFiles.add(file);
+ }
+ return CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ if (pathMatcher.matches(dir)) {
+ Set<Path> filesToAdd = CSARImporter.this.getAllFiles(dir);
+ allFiles.addAll(filesToAdd);
+ return SKIP_SUBTREE;
+ } else {
+ return CONTINUE;
+ }
+ }
+ });
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * Lists all files contained in the given path
+ */
+ private Set<Path> getAllFiles(Path startPath) {
+ final Set<Path> res = new HashSet<>();
+ try {
+ Files.walkFileTree(startPath, new SimpleFileVisitor<Path>() {
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ res.add(file);
+ return CONTINUE;
+ }
+ });
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ return res;
+ }
+
+ /**
+ * Sets the namespace on the CI if CI offers the method "setTargetNamespace"
+ *
+ * @param ci the component instance to set the namespace
+ * @param namespace the namespace to set
+ */
+ private void setNamespace(TExtensibleElements ci, String namespace) {
+ Method method;
+ try {
+ method = ci.getClass().getMethod("setTargetNamespace", String.class);
+ method.invoke(ci, namespace);
+ } catch (NoSuchMethodException ne) {
+ // this is OK, because we do not check, whether the method really exists
+ // Special case for TArtifactTemplate not offering setTargetNamespace
+ // just ignore it
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not set target namespace", e);
+ }
+ }
+
+ /**
+ * @param ci the component instance to get the namespace from
+ * @param defaultNamespace the namespace to use if the TExtensibleElements
+ * has no targetNamespace
+ */
+ private String getNamespace(TExtensibleElements ci, String defaultNamespace) {
+ Method method;
+ Object res;
+ try {
+ method = ci.getClass().getMethod("getTargetNamespace");
+ res = method.invoke(ci);
+ } catch (Exception e) {
+ // we are at TArtifactTemplate, which does not offer getTargetNamespace
+ res = null;
+ }
+ String ns = (String) res;
+ if (ns == null) {
+ ns = defaultNamespace;
+ }
+ return ns;
+ }
+
+ /**
+ * @param basePath the base path where to resolve files from. This is the
+ * directory of the Definitions
+ * @param imports the list of imports to import. SIDE EFFECT: this list is
+ * modified. After this method has run, the list contains the
+ * imports to be put into the wrapper element
+ */
+ private void importImports(Path basePath, TOSCAMetaFile tmf, List<TImport> imports, final List<String> errors, boolean overwrite, final boolean asyncWPDParsing) throws IOException {
+ for (Iterator<TImport> iterator = imports.iterator(); iterator.hasNext();) {
+ TImport imp = iterator.next();
+ String importType = imp.getImportType();
+ String namespace = imp.getNamespace();
+ String loc = imp.getLocation();
+
+ if (namespace == null) {
+ errors.add("not namespace-qualified imports are not supported.");
+ continue;
+ }
+
+ if (loc == null) {
+ errors.add("Empty location imports are not supported.");
+ } else {
+ if (importType.equals(Namespaces.TOSCA_NAMESPACE)) {
+ if (!Util.isRelativeURI(loc)) {
+ errors.add("Absolute URIs for definitions import not supported.");
+ continue;
+ }
+
+ // URIs are encoded
+ loc = Util.URLdecode(loc);
+
+ Path defsPath = basePath.resolve(loc);
+ // fallback for older CSARs, where the location is given from the root
+ if (!Files.exists(defsPath)) {
+ defsPath = basePath.getParent().resolve(loc);
+ // the real existence check is done in importDefinitions
+ }
+ this.importDefinitions(tmf, defsPath, errors, overwrite, asyncWPDParsing);
+ // imports of definitions don't have to be kept as these are managed by Winery
+ iterator.remove();
+ } else {
+ this.importOtherImport(basePath, imp, errors, importType, overwrite);
+ }
+ }
+ }
+ }
+
+ /**
+ * SIDE EFFECT: modifies the location of imp to point to the correct
+ * relative location (when read from the exported CSAR)
+ *
+ * @param rootPath the absolute path where to resolve files from
+ */
+ private void importOtherImport(Path rootPath, TImport imp, final List<String> errors, String type, boolean overwrite) {
+ assert (!type.equals(Namespaces.TOSCA_NAMESPACE));
+ String loc = imp.getLocation();
+
+ if (!Util.isRelativeURI(loc)) {
+ // This is just an information message
+ errors.add("Absolute URIs are not resolved by Winery (" + loc + ")");
+ return;
+ }
+
+ // location URLs are encoded: http://www.w3.org/TR/2001/WD-charmod-20010126/#sec-URIs, RFC http://www.ietf.org/rfc/rfc2396.txt
+ loc = Util.URLdecode(loc);
+ Path path;
+ try {
+ path = rootPath.resolve(loc);
+ } catch (Exception e) {
+ // java.nio.file.InvalidPathException could be thrown which is a RuntimeException
+ errors.add(e.getMessage());
+ return;
+ }
+ if (!Files.exists(path)) {
+ // fallback for older CSARs, where the location is given from the root
+ path = rootPath.getParent().resolve(loc);
+ if (!Files.exists(path)) {
+ errors.add(String.format("File %1$s does not exist", loc));
+ return;
+ }
+ }
+ String namespace = imp.getNamespace();
+ String fileName = path.getFileName().toString();
+ String id = fileName;
+ id = FilenameUtils.removeExtension(id);
+ // Convention: id of import is filename without extension
+
+ GenericImportId rid;
+ if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
+ rid = new XSDImportId(namespace, id, false);
+ } else {
+ rid = new GenericImportId(namespace, id, false, type);
+ }
+
+ boolean importDataExistsInRepo = Repository.INSTANCE.exists(rid);
+
+ if (!importDataExistsInRepo) {
+ // We have to
+ // a) create a .definitions file
+ // b) put the file itself in the repo
+
+ // Create the definitions file
+ TDefinitions defs = BackendUtils.createWrapperDefinitions(rid);
+ defs.getImport().add(imp);
+ // QUICK HACK: We change the imp object's location here and below again
+ // This is "OK" as "storeDefinitions" serializes the current state and not the future state of the imp object
+ // change the location to point to the file in the folder of the .definitions file
+ imp.setLocation(fileName);
+
+ // put the definitions file to the repository
+ CSARImporter.storeDefinitions(rid, defs);
+ }
+
+ // put the file itself to the repo
+ // ref is required to generate fileRef
+ RepositoryFileReference ref = BackendUtils.getRefOfDefinitions(rid);
+ RepositoryFileReference fileRef = new RepositoryFileReference(ref.getParent(), fileName);
+
+ // location is relative to Definitions/
+ // even if the import already exists, we have to adapt the path
+ // URIs are encoded
+ String newLoc = "../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(fileRef));
+ imp.setLocation(newLoc);
+
+ if (!importDataExistsInRepo || overwrite) {
+ // finally write the file to the storage
+ try (InputStream is = Files.newInputStream(path);
+ BufferedInputStream bis = new BufferedInputStream(is)) {
+ MediaType mediaType;
+ if (type.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
+ mediaType = MediaType.valueOf(MimeTypes.MIMETYPE_XSD);
+ } else {
+ String mimeType = Utils.getMimeType(bis, path.getFileName().toString());
+ mediaType = MediaType.valueOf(mimeType);
+ }
+ Repository.INSTANCE.putContentToFile(fileRef, bis, mediaType);
+ } catch (IllegalArgumentException | IOException e) {
+ throw new IllegalStateException(e);
+ }
+
+ // we have to update the cache in case of a new XSD to speedup usage of winery
+ if (rid instanceof XSDImportId) {
+ // We do the initialization asynchronously
+ // We do not check whether the XSD has already been checked
+ // We cannot just checck whether an XSD already has been handled since the XSD could change over time
+ // Synchronization at org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportResource.getAllDefinedLocalNames(short) also isn't feasible as the backend doesn't support locks
+ CSARImporter.xsdParsingService.submit(new Runnable() {
+
+ @Override
+ public void run() {
+ CSARImporter.logger.debug("Updating XSD import cache data");
+ // We call the queries without storing the result:
+ // We use the SIDEEFFECT that a cache is created
+ Utils.getAllXSDElementDefinitionsForTypeAheadSelection();
+ Utils.getAllXSDTypeDefinitionsForTypeAheadSelection();
+ CSARImporter.logger.debug("Updated XSD import cache data");
+ }
+ });
+ }
+ }
+ }
+
+ private static void storeDefinitions(TOSCAComponentId id, TDefinitions defs) {
+ RepositoryFileReference ref = BackendUtils.getRefOfDefinitions(id);
+ String s = Utils.getXMLAsString(defs, true);
+ try {
+ Repository.INSTANCE.putContentToFile(ref, s, MediaType.valueOf(MimeTypes.MIMETYPE_TOSCA_DEFINITIONS));
+ } catch (IllegalArgumentException | IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java
new file mode 100644
index 0000000..72d2220
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TTopologyTemplateSerializer.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.json;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.model.tosca.TTopologyTemplate;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+
+public class TTopologyTemplateSerializer extends JsonSerializer<TTopologyTemplate> {
+
+ /**
+ * Does NOT wrap the result into an object. Assumes that the current
+ * position at jgen is in an object
+ *
+ * @param value the list of entity templates to serialize
+ */
+ public void serialize(List<TEntityTemplate> value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
+ List<TRelationshipTemplate> relationshipTemplates = new ArrayList<TRelationshipTemplate>();
+
+ jgen.writeFieldName("nodeTemplates");
+ jgen.writeStartObject();
+ for (TEntityTemplate template : value) {
+ if (template instanceof TNodeTemplate) {
+ // write out as <id> : <default serialization>
+ jgen.writeFieldName(template.getId());
+ provider.defaultSerializeValue(template, jgen);
+
+ } else {
+ assert (template instanceof TRelationshipTemplate);
+ relationshipTemplates.add((TRelationshipTemplate) template);
+ }
+ }
+ jgen.writeEndObject();
+
+ jgen.writeFieldName("relationshipTemplates");
+ jgen.writeStartObject();
+ for (TRelationshipTemplate template : relationshipTemplates) {
+ // write out as <id> : <default serialization>
+ jgen.writeFieldName(template.getId());
+ provider.defaultSerializeValue(template, jgen);
+ }
+ jgen.writeEndObject();
+ }
+
+ @Override
+ public void serialize(TTopologyTemplate topologyTemplate, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
+ jgen.writeStartObject();
+
+ // write out the other fields unmodified
+ jgen.writeFieldName("documentation");
+ provider.defaultSerializeValue(topologyTemplate.getDocumentation(), jgen);
+ jgen.writeFieldName("any");
+ provider.defaultSerializeValue(topologyTemplate.getAny(), jgen);
+ jgen.writeFieldName("otherAttributes");
+ provider.defaultSerializeValue(topologyTemplate.getOtherAttributes(), jgen);
+
+ // finally, write the topology template
+ this.serialize(topologyTemplate.getNodeTemplateOrRelationshipTemplate(), jgen, provider);
+
+ jgen.writeEndObject();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java
new file mode 100644
index 0000000..e5d9950
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/json/TopologyTemplateModule.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.json;
+
+import org.eclipse.winery.model.tosca.TTopologyTemplate;
+
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+@SuppressWarnings("serial")
+public class TopologyTemplateModule extends SimpleModule {
+
+ public TopologyTemplateModule() {
+ this.addSerializer(TTopologyTemplate.class, new TTopologyTemplateSerializer());
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java
new file mode 100644
index 0000000..9393b7e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/APIResource.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.API;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.select2.Select2DataWithOptGroups;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+
+public class APIResource {
+
+ @GET
+ @Path("getallartifacttemplatesofcontaineddeploymentartifacts")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getAllArtifactTemplatesOfContainedDeploymentArtifacts(@QueryParam("servicetemplate") String serviceTemplateQNameString, @QueryParam("nodetemplateid") String nodeTemplateId) {
+ if (StringUtils.isEmpty(serviceTemplateQNameString)) {
+ return Response.status(Status.BAD_REQUEST).entity("servicetemplate has be given as query parameter").build();
+ }
+
+ QName serviceTemplateQName = QName.valueOf(serviceTemplateQNameString);
+
+ ServiceTemplateId serviceTemplateId = new ServiceTemplateId(serviceTemplateQName);
+ if (!Repository.INSTANCE.exists(serviceTemplateId)) {
+ return Response.status(Status.BAD_REQUEST).entity("service template does not exist").build();
+ }
+ ServiceTemplateResource serviceTemplateResource = new ServiceTemplateResource(serviceTemplateId);
+
+ Collection<QName> artifactTemplates = new ArrayList<>();
+ List<TNodeTemplate> allNestedNodeTemplates = BackendUtils.getAllNestedNodeTemplates(serviceTemplateResource.getServiceTemplate());
+ for (TNodeTemplate nodeTemplate : allNestedNodeTemplates) {
+ if (StringUtils.isEmpty(nodeTemplateId) || nodeTemplate.getId().equals(nodeTemplateId)) {
+ Collection<QName> ats = BackendUtils.getArtifactTemplatesOfReferencedDeploymentArtifacts(nodeTemplate);
+ artifactTemplates.addAll(ats);
+ }
+ }
+
+ // convert QName list to select2 data
+ Select2DataWithOptGroups res = new Select2DataWithOptGroups();
+ for (QName qName : artifactTemplates) {
+ res.add(qName.getNamespaceURI(), qName.toString(), qName.getLocalPart());
+ }
+ return Response.ok().entity(res.asSortedSet()).build();
+ }
+
+ /**
+ * Implementation similar to
+ * getAllArtifactTemplatesOfContainedDeploymentArtifacts. Only difference is
+ * "getArtifactTemplatesOfReferencedImplementationArtifacts" instead of
+ * "getArtifactTemplatesOfReferencedDeploymentArtifacts".
+ */
+ @GET
+ @Path("getallartifacttemplatesofcontainedimplementationartifacts")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getAllArtifactTemplatesOfContainedImplementationArtifacts(@QueryParam("servicetemplate") String serviceTemplateQNameString, @QueryParam("nodetemplateid") String nodeTemplateId) {
+ if (StringUtils.isEmpty(serviceTemplateQNameString)) {
+ return Response.status(Status.BAD_REQUEST).entity("servicetemplate has be given as query parameter").build();
+ }
+ QName serviceTemplateQName = QName.valueOf(serviceTemplateQNameString);
+
+ ServiceTemplateId serviceTemplateId = new ServiceTemplateId(serviceTemplateQName);
+ if (!Repository.INSTANCE.exists(serviceTemplateId)) {
+ return Response.status(Status.BAD_REQUEST).entity("service template does not exist").build();
+ }
+ ServiceTemplateResource serviceTemplateResource = new ServiceTemplateResource(serviceTemplateId);
+
+ Collection<QName> artifactTemplates = new ArrayList<>();
+ List<TNodeTemplate> allNestedNodeTemplates = BackendUtils.getAllNestedNodeTemplates(serviceTemplateResource.getServiceTemplate());
+ for (TNodeTemplate nodeTemplate : allNestedNodeTemplates) {
+ if (StringUtils.isEmpty(nodeTemplateId) || nodeTemplate.getId().equals(nodeTemplateId)) {
+ Collection<QName> ats = BackendUtils.getArtifactTemplatesOfReferencedImplementationArtifacts(nodeTemplate);
+ artifactTemplates.addAll(ats);
+ }
+ }
+
+ // convert QName list to select2 data
+ Select2DataWithOptGroups res = new Select2DataWithOptGroups();
+ for (QName qName : artifactTemplates) {
+ res.add(qName.getNamespaceURI(), qName.toString(), qName.getLocalPart());
+ }
+ return Response.ok().entity(res.asSortedSet()).build();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java
new file mode 100644
index 0000000..6eda321
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/API/package-info.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+/**
+ * This package contains all packages providing extended access to the stored models
+ *
+ * The idea is that the resources provide information stored in the respective definition file.
+ * With this API, the stored data is interpreted more abstractly. As a long-term goal, things
+ * such as inherticance should be supported here
+ */
+package org.eclipse.winery.repository.resources.API; \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java
new file mode 100644
index 0000000..d4cc201
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResource.java
@@ -0,0 +1,516 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.StreamingOutput;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.TOSCADocumentBuilderFactory;
+import org.eclipse.winery.common.constants.MimeTypes;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.model.tosca.Definitions;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImport;
+import org.eclipse.winery.repository.JAXBSupport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.constants.MediaTypes;
+import org.eclipse.winery.repository.export.TOSCAExportUtil;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources.documentation.DocumentationsResource;
+import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportResource;
+import org.eclipse.winery.repository.resources.tags.TagsResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Resource for a component (
+ * <ul>
+ * <li>ServiceTemplates,</li>
+ * <li>EntityTypes,</li>
+ * <li>EntityTypeImplementations,</li>
+ * <li>EntityTemplates</li>
+ * </ul>
+ * ). A component is directly nested in a TDefinitions element. See also
+ * {@link org.eclipse.winery.common.ids.definitions.TOSCAComponentId}
+ *
+ * Bundles all operations required for all components. e.g., namespace+XMLid,
+ * object comparison, import, export, tags
+ *
+ * Uses a TDefinitions document as storage.
+ *
+ * Additional setters and getters are added if it comes to Winery's extensions
+ * such as the color of a relationship type
+ */
+public abstract class AbstractComponentInstanceResource implements Comparable<AbstractComponentInstanceResource>, IPersistable {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractComponentInstanceResource.class);
+
+ protected final TOSCAComponentId id;
+
+ private final RepositoryFileReference ref;
+
+ // the object representing the data of this resource
+ private Definitions definitions = null;
+
+ // shortcut for this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
+ protected TExtensibleElements element = null;
+
+
+ /**
+ * Instantiates the resource. Assumes that the resource should exist
+ * (assured by the caller)
+ *
+ * The caller should <em>not</em> create the resource by other ways. E.g.,
+ * by instantiating this resource and then adding data.
+ */
+ public AbstractComponentInstanceResource(TOSCAComponentId id) {
+ this.id = id;
+
+ // the resource itself exists
+ assert (Repository.INSTANCE.exists(id));
+
+ // the data file might not exist
+ this.ref = BackendUtils.getRefOfDefinitions(id);
+ if (Repository.INSTANCE.exists(this.ref)) {
+ this.load();
+ } else {
+ this.createNew();
+ }
+ }
+
+ /**
+ * Convenience method for getId().getNamespace()
+ */
+ public final Namespace getNamespace() {
+ return this.id.getNamespace();
+ }
+
+ /**
+ * Convenience method for getId().getXmlId()
+ */
+ public final XMLId getXmlId() {
+ return this.id.getXmlId();
+ }
+
+ /**
+ * Convenience method for getId().getQName();
+ *
+ * @return the QName associated with this resource
+ */
+ public final QName getQName() {
+ return this.getId().getQName();
+ }
+
+ /**
+ * Returns the id associated with this resource
+ */
+ public final TOSCAComponentId getId() {
+ return this.id;
+ }
+
+ /**
+ * called from AbstractComponentResource
+ */
+ @DELETE
+ public final Response onDelete() {
+ Response res = BackendUtils.delete(this.id);
+ return res;
+ }
+
+ @Override
+ public final int compareTo(AbstractComponentInstanceResource o) {
+ return this.id.compareTo(o.id);
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof String) {
+ throw new IllegalStateException();
+ } else if (o instanceof AbstractComponentInstanceResource) {
+ if (o.getClass().equals(this.getClass())) {
+ // only compare if the two objects are from the same class
+ return ((AbstractComponentInstanceResource) o).getId().equals(this.getId());
+ } else {
+ throw new IllegalStateException();
+ }
+ } else {
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public final int hashCode() {
+ return this.getId().hashCode();
+ }
+
+ @GET
+ @Path("id")
+ public String getTOSCAId() {
+ return this.id.getXmlId().getDecoded();
+ }
+
+ @PUT
+ @Path("id")
+ public Response putId(@FormParam("id") String id) {
+ // this renames the entity type resource
+ // TODO: implement rename functionality
+ return Response.serverError().entity("not yet implemented").build();
+ }
+
+ /**
+ * Main page
+ */
+ // @Produces(MediaType.TEXT_HTML) // not true because of ?csar leads to send
+ // a csar. We nevertheless have to annotate that to be able to get a JSON
+ // representation required for the file upload (in {@link
+ // ArtifactTemplateResource})
+ //
+ // we cannot issue a request expecting content-type application/zip as it is
+ // not possible to offer the result in a "save-as"-dialog:
+ // http://stackoverflow.com/questions/7464665/ajax-response-content-disposition-attachment
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public final Response getHTML(@QueryParam(value = "definitions") String definitions, @QueryParam(value = "csar") String csar, @Context UriInfo uriInfo) {
+ if (!Repository.INSTANCE.exists(this.id)) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ if (definitions != null) {
+ return Utils.getDefinitionsOfSelectedResource(this, uriInfo.getBaseUri());
+ } else if (csar != null) {
+ return this.getCSAR();
+ } else {
+ String type = Utils.getTypeForInstance(this.getClass());
+ String viewableName = "/jsp/" + Utils.getIntermediateLocationStringForType(type, "/") + "/" + type.toLowerCase() + ".jsp";
+ Viewable viewable = new Viewable(viewableName, this);
+
+ return Response.ok().entity(viewable).build();
+
+ // we can't do the following as the GET request from the browser
+ // cannot set the accept header properly
+ // "vary: accept" header has to be set as we may also return a THOR
+ // on the same URL
+ // return Response.ok().header(HttpHeaders.VARY,
+ // HttpHeaders.ACCEPT).entity(viewable).build();
+ }
+ }
+
+ @GET
+ @Produces(MimeTypes.MIMETYPE_ZIP)
+ public final Response getCSAR() {
+ if (!Repository.INSTANCE.exists(this.id)) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ return Utils.getCSARofSelectedResource(this);
+ }
+
+ /**
+ * Returns the definitions of this resource. Includes required imports of
+ * other definitions
+ *
+ * @param csar used because plan generator's GET request lands here
+ */
+ @GET
+ @Produces({MimeTypes.MIMETYPE_TOSCA_DEFINITIONS, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ public Response getDefinitionsAsResponse(@QueryParam(value = "csar") String csar) {
+ if (!Repository.INSTANCE.exists(this.id)) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+
+ if (csar != null) {
+ return Utils.getCSARofSelectedResource(this);
+ }
+
+ StreamingOutput so = new StreamingOutput() {
+
+ @Override
+ public void write(OutputStream output) throws IOException, WebApplicationException {
+ TOSCAExportUtil exporter = new TOSCAExportUtil();
+ // we include everything related
+ Map<String, Object> conf = new HashMap<>();
+ try {
+ exporter.exportTOSCA(AbstractComponentInstanceResource.this.id, output, conf);
+ } catch (JAXBException e) {
+ throw new WebApplicationException(e);
+ }
+ }
+ };
+ return Response.ok().type(MediaType.TEXT_XML).entity(so).build();
+ }
+
+ /**
+ * @throws IllegalStateException if an IOException occurred. We opted not to
+ * propagate the IOException directly as this exception occurs
+ * seldom and is a not an exception to be treated by all callers
+ * in the prototype.
+ */
+ private void load() {
+ try {
+ InputStream is = Repository.INSTANCE.newInputStream(this.ref);
+ Unmarshaller u = JAXBSupport.createUnmarshaller();
+ this.definitions = (Definitions) u.unmarshal(is);
+ } catch (Exception e) {
+ AbstractComponentInstanceResource.logger.error("Could not read content from file " + this.ref, e);
+ throw new IllegalStateException(e);
+ }
+ try {
+ this.element = this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
+ } catch (IndexOutOfBoundsException e) {
+ if (this instanceof GenericImportResource) {
+ // everything allright:
+ // ImportResource is a quick hack using 99% of the functionality offered here
+ // As only 1% has to be "quick hacked", we do that instead of a clean design
+ // Clean design: Introduce a class between this and AbstractComponentInstanceResource, where this class and ImportResource inhertis from
+ // A clean design introducing a super class AbstractDefinitionsBackedResource does not work, as we currently also support PropertiesBackedResources and such a super class would required multi-inheritance
+ } else {
+ throw new IllegalStateException("Wrong storage format: No ServiceTemplateOrNodeTypeOrNodeTypeImplementation found.");
+ }
+ }
+ }
+
+ @Override
+ public void persist() throws IOException {
+ BackendUtils.persist(this.definitions, this.ref, MediaTypes.MEDIATYPE_TOSCA_DEFINITIONS);
+ }
+
+ /**
+ * Creates a new instance of the object represented by this resource
+ */
+ private void createNew() {
+ this.definitions = BackendUtils.createWrapperDefinitions(this.getId());
+
+ // create empty element
+ this.element = this.createNewElement();
+
+ // add the element to the definitions
+ this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().add(this.element);
+
+ // copy ns + id
+ this.copyIdToFields();
+
+ // ensure that the definitions is persisted. Ensures that export works.
+ BackendUtils.persist(this);
+ }
+
+ /**
+ * Creates an empty instance of an Element.
+ *
+ * The implementors do <em>not</em>have to copy the ns and the id to the
+ * appropriate fields.
+ *
+ * we have two implementation possibilities:
+ * <ul>
+ * <li>a) each subclass implements this method and returns the appropriate
+ * object</li>
+ * <li>b) we use java reflection to invoke the right constructor as done in
+ * the resources</li>
+ * </ul>
+ * We opted for a) to increase readability of the code
+ */
+ protected abstract TExtensibleElements createNewElement();
+
+ /**
+ * Copies the current id of the resource to the appropriate fields in the
+ * element.
+ *
+ * For instance, the id is put in the "name" field for EntityTypes
+ *
+ * We opted for a separate method from createNewElement to enable renaming
+ * of the object
+ */
+ protected abstract void copyIdToFields();
+
+ /**
+ * Returns the Element belonging to this resource. As Java does not allow
+ * overriding returned classes, we expect the caller to either cast right or
+ * to use "getXY" defined by each subclass, where XY is the concrete type
+ *
+ * Shortcut for
+ * getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation
+ * ().get(0);
+ *
+ * @return TCapabilityType|...
+ */
+ public TExtensibleElements getElement() {
+ return this.element;
+ }
+
+ /**
+ * @return the reference to the internal list of imports. Can be changed if
+ * some imports are required or should be removed
+ * @throws IllegalStateException if definitions was not loaded or not
+ * initialized
+ */
+ protected List<TImport> getImport() {
+ if (this.definitions == null) {
+ throw new IllegalStateException("Trying to access uninitalized definitions object");
+ }
+ return this.definitions.getImport();
+ }
+
+ /**
+ * Returns an XML representation of the definitions
+ *
+ * We return the complete definitions to allow the user changes to it, such
+ * as adding imports, etc.
+ */
+ public String getDefinitionsAsXMLString() {
+ StringWriter w = new StringWriter();
+ Marshaller m = JAXBSupport.createMarshaller(true);
+ try {
+ m.marshal(this.definitions, w);
+ } catch (JAXBException e) {
+ AbstractComponentInstanceResource.logger.error("Could not marshal definitions", e);
+ throw new IllegalStateException(e);
+ }
+ String res = w.toString();
+ return res;
+ }
+
+ /**
+ * @return the reference to the internal Definitions object
+ */
+ public Definitions getDefinitions() {
+ return this.definitions;
+ }
+
+ @PUT
+ @Consumes({MimeTypes.MIMETYPE_TOSCA_DEFINITIONS, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ public Response updateDefinitions(InputStream requestBodyStream) {
+ Unmarshaller u;
+ Definitions defs;
+ Document doc;
+ final StringBuilder sb = new StringBuilder();
+ try {
+ DocumentBuilder db = TOSCADocumentBuilderFactory.INSTANCE.getTOSCADocumentBuilder();
+ db.setErrorHandler(new ErrorHandler() {
+
+ @Override
+ public void warning(SAXParseException exception) throws SAXException {
+ // we don't care
+ }
+
+ @Override
+ public void fatalError(SAXParseException exception) throws SAXException {
+ sb.append("Fatal Error: ");
+ sb.append(exception.getMessage());
+ sb.append("\n");
+ }
+
+ @Override
+ public void error(SAXParseException exception) throws SAXException {
+ sb.append("Fatal Error: ");
+ sb.append(exception.getMessage());
+ sb.append("\n");
+ }
+ });
+ doc = db.parse(requestBodyStream);
+ if (sb.length() > 0) {
+ // some error happened
+ // doc is not null, because the parser parses even if it is not XSD conforming
+ return Response.status(Status.BAD_REQUEST).entity(sb.toString()).build();
+ }
+ } catch (SAXException | IOException e) {
+ AbstractComponentInstanceResource.logger.debug("Could not parse XML", e);
+ return Utils.getResponseForException(e);
+ }
+ try {
+ u = JAXBSupport.createUnmarshaller();
+ defs = (Definitions) u.unmarshal(doc);
+ } catch (JAXBException e) {
+ AbstractComponentInstanceResource.logger.debug("Could not unmarshal from request body stream", e);
+ return Utils.getResponseForException(e);
+ }
+
+ // initial validity check
+
+ // we allow changing the target namespace and the id
+ // This allows for inserting arbitrary definitions XML
+ // if (!this.definitions.getTargetNamespace().equals(this.id.getNamespace().getDecoded())) {
+ // return Response.status(Status.BAD_REQUEST).entity("Changing of the namespace is not supported").build();
+ // }
+ // this.definitions.setTargetNamespace(this.id.getNamespace().getDecoded());
+
+ // TODO: check the provided definitions for validity
+
+ TExtensibleElements tExtensibleElements = defs.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
+ if (!tExtensibleElements.getClass().equals(this.createNewElement().getClass())) {
+ return Response.status(Status.BAD_REQUEST).entity("First type in Definitions is not matching the type modeled by this resource").build();
+ }
+
+ this.definitions = defs;
+
+ // replace existing element by retrieved data
+ this.element = this.definitions.getServiceTemplateOrNodeTypeOrNodeTypeImplementation().get(0);
+
+ // ensure that ids did not change
+ // TODO: future work: raise error if user changed id or namespace
+ this.copyIdToFields();
+
+ return BackendUtils.persist(this);
+ }
+
+ @GET
+ @Path("xml/")
+ @Produces(MediaType.TEXT_HTML)
+ public Response getXML() {
+ Viewable viewable = new Viewable("/jsp/xmlSource.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+
+ @Path("documentation/")
+ public DocumentationsResource getDocumentationsResource() {
+ return new DocumentationsResource(this, this.getElement().getDocumentation());
+ }
+
+ @Path("tags/")
+ public final TagsResource getTags() {
+ return new TagsResource(this.id);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java
new file mode 100644
index 0000000..7bc7c73
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.lang.reflect.Method;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.model.tosca.TBoolean;
+import org.eclipse.winery.model.tosca.TEntityType.DerivedFrom;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Models a component instance with name, derived from, abstract, and final <br />
+ * Tags are provided by AbstractComponentInstanceResource
+ *
+ * This class mirrors
+ * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinalConfigurationBacked
+ * . We did not include interfaces as the getters are currently only called at
+ * the jsp
+ */
+public abstract class AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal extends AbstractComponentInstanceResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.class);
+
+
+ protected AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal(TOSCAComponentId id) {
+ super(id);
+ }
+
+ /**
+ * @return The associated name of this resource. CSDPR01 foresees a NCName
+ * name and no ID for an entity type. Therefore, we use the ID as
+ * unique identification and convert it to a name when a read
+ * request is put.
+ */
+ @GET
+ @Path("name")
+ public String getName() {
+ return ModelUtilities.getName(this.getElement());
+ }
+
+ @PUT
+ @Path("name")
+ public Response putName(String name) {
+ ModelUtilities.setName(this.getElement(), name);
+ return BackendUtils.persist(this);
+ }
+
+ @GET
+ @Path("derivedFrom")
+ public String getDerivedFrom() {
+ // TOSCA does not introduce a type like WithNameDerivedFromAbstractFinal
+ // We could enumerate all possible implementing classes
+ // Or use java reflection, what we're doing now.
+ Method method;
+ // We have three different "DerivedFrom", for NodeTypeImplementation and RelationshipTypeImplementation, we have to assign to a different "DerivedFrom"
+ // This has to be done in the derived resources
+ DerivedFrom derivedFrom;
+ try {
+ method = this.getElement().getClass().getMethod("getDerivedFrom");
+ derivedFrom = (DerivedFrom) method.invoke(this.getElement());
+ } catch (ClassCastException e) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Seems that *Implementation is now Definitions backed, but not yet fully implented", e);
+ throw new IllegalStateException(e);
+ } catch (Exception e) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not get derivedFrom", e);
+ throw new IllegalStateException(e);
+ }
+ if (derivedFrom == null) {
+ return null;
+ }
+ QName typeRef = derivedFrom.getTypeRef();
+ if (typeRef == null) {
+ return null;
+ } else {
+ return typeRef.toString();
+ }
+ }
+
+ @PUT
+ @Path("derivedFrom")
+ public Response putDerivedFrom(String type) {
+ QName qname = QName.valueOf(type);
+
+ // see getDerivedFrom for verbose comments
+ Method method;
+ DerivedFrom derivedFrom = new DerivedFrom();
+ derivedFrom.setTypeRef(qname);
+ try {
+ method = this.getElement().getClass().getMethod("setDerivedFrom", DerivedFrom.class);
+ method.invoke(this.getElement(), derivedFrom);
+ } catch (ClassCastException e) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Seems that *Implementation is now Definitions backed, but not yet fully implemented", e);
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build();
+ } catch (Exception e) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not set derivedFrom", e);
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build();
+ }
+
+ return BackendUtils.persist(this);
+ }
+
+ /**
+ * @param methodName the method to call: getAbstract|getFinal
+ * @return {@inheritDoc}
+ */
+ private String getTBoolean(String methodName) {
+ // see getDerivedFrom for verbose comments
+ Method method;
+ TBoolean tBoolean;
+ try {
+ method = this.getElement().getClass().getMethod(methodName);
+ tBoolean = (TBoolean) method.invoke(this.getElement());
+ } catch (Exception e) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not get boolean " + methodName, e);
+ throw new IllegalStateException(e);
+ }
+ if (tBoolean == null) {
+ return null;
+ } else {
+ return tBoolean.value();
+ }
+ }
+
+ /**
+ * @param methodName the method to call: setAbstract|setFinal
+ * @return {@inheritDoc}
+ */
+ private Response putTBoolean(String tBooleanStr, String methodName) {
+ // see getDerivedFrom for verbose comments
+
+ Method method;
+ TBoolean tBoolean = TBoolean.fromValue(tBooleanStr);
+ try {
+ method = this.getElement().getClass().getMethod(methodName, TBoolean.class);
+ method.invoke(this.getElement(), tBoolean);
+ } catch (Exception e) {
+ AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal.logger.error("Could not set tBoolean " + methodName, e);
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build();
+ }
+
+ return BackendUtils.persist(this);
+ }
+
+ /**
+ * Method name is not "getAbstract" as ${it.abstract} does not work as
+ * "abstract" is not allowed at that place
+ */
+ @GET
+ @Path("abstract")
+ public String getIsAbstract() {
+ return this.getTBoolean("getAbstract");
+ }
+
+ @PUT
+ @Path("abstract")
+ public Response putIsAbstract(String isAbstract) {
+ return this.putTBoolean(isAbstract, "setAbstract");
+ }
+
+ @GET
+ @Path("final")
+ public String getIsFinal() {
+ return this.getTBoolean("getFinal");
+ }
+
+ @PUT
+ @Path("final")
+ public Response putIsFinal(String isFinal) {
+ return this.putTBoolean(isFinal, "setFinal");
+ }
+
+ /**
+ * @return resource managing abstract, final, derivedFrom
+ */
+ @Path("inheritance/")
+ public InheritanceResource getInheritanceManagement() {
+ return new InheritanceResource(this);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java
new file mode 100644
index 0000000..3b63b0f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentInstanceWithReferencesResource.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.Definitions;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+
+public abstract class AbstractComponentInstanceWithReferencesResource extends AbstractComponentInstanceResource {
+
+ public AbstractComponentInstanceWithReferencesResource(TOSCAComponentId id) {
+ super(id);
+ }
+
+ /**
+ * Ensures that the presented XML is in line with the stored files
+ */
+ @Override
+ public Response getXML() {
+ this.synchronizeReferences();
+ return super.getXML();
+ }
+
+ @Override
+ public String getDefinitionsAsXMLString() {
+ this.synchronizeReferences();
+ return super.getDefinitionsAsXMLString();
+ }
+
+ @Override
+ public Definitions getDefinitions() {
+ this.synchronizeReferences();
+ return super.getDefinitions();
+ }
+
+ /**
+ * Synchronizes the artifact references with the files stored in the
+ * repository
+ */
+ public abstract void synchronizeReferences();
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java
new file mode 100644
index 0000000..5702376
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsResource.java
@@ -0,0 +1,279 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.io.StringWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.SortedSet;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.ResourceCreationResult;
+import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.sun.jersey.api.NotFoundException;
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Resource handling of a set of components. Each component has to provide a
+ * class to handle the set. This is required to provide the correct instances of
+ * TOSCAcomponentIds.
+ *
+ * TODO: Add generics here!
+ * {@link Utils.getComponentIdClassForComponentContainer} is then obsolete
+ */
+public abstract class AbstractComponentsResource<R extends AbstractComponentInstanceResource> {
+
+ protected static final Logger logger = LoggerFactory.getLogger(AbstractComponentsResource.class);
+
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML() {
+ return Response.ok().entity(new Viewable("/jsp/genericcomponentpage.jsp", new GenericComponentPageData(this.getClass()))).build();
+ }
+
+ /**
+ * Creates a new component instance in the given namespace
+ *
+ * @param namespace plain namespace
+ * @param id plain id
+ */
+ protected ResourceCreationResult onPost(String namespace, String name) {
+ ResourceCreationResult res;
+ if (StringUtils.isEmpty(namespace) || StringUtils.isEmpty(name)) {
+ res = new ResourceCreationResult(Status.BAD_REQUEST);
+ } else {
+ String id = Utils.createXMLidAsString(name);
+ TOSCAComponentId tcId;
+ try {
+ tcId = this.getTOSCAcomponentId(namespace, id, false);
+ res = this.createComponentInstance(tcId);
+ // in case the resource additionally supports a name attribute, we set the original name
+ if (res.getStatus().equals(Status.CREATED)) {
+ if ((tcId instanceof ServiceTemplateId) || (tcId instanceof ArtifactTemplateId) || (tcId instanceof PolicyTemplateId)) {
+ // these three types have an additional name (instead of a pure id)
+ // we store the name
+ IHasName resource = (IHasName) AbstractComponentsResource.getComponentInstaceResource(tcId);
+ resource.setName(name);
+ }
+ }
+ } catch (Exception e) {
+ AbstractComponentsResource.logger.debug("Could not create id instance", e);
+ res = new ResourceCreationResult(Status.INTERNAL_SERVER_ERROR);
+ }
+ }
+ return res;
+ }
+
+ /**
+ * Creates a new component instance in the given namespace
+ *
+ * @param namespace plain namespace
+ * @param id plain id
+ * @param ignored this parameter is ignored, but necessary for
+ * {@link ArtifactTemplatesResource} to be able to accept the
+ * artifact type at a post
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response onPost(@FormParam("namespace") String namespace, @FormParam("name") String name, String ignored) {
+ ResourceCreationResult res = this.onPost(namespace, name);
+ return res.getResponse();
+ }
+
+ /**
+ * Creates a TOSCAcomponentId for the given namespace / id combination
+ *
+ * Uses reflection to create a new instance
+ */
+ protected TOSCAComponentId getTOSCAcomponentId(String namespace, String id, boolean URLencoded) throws Exception {
+ Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass());
+ return BackendUtils.getTOSCAcomponentId(idClass, namespace, id, URLencoded);
+ }
+
+ /**
+ * Creates a new instance of the current component
+ *
+ * @return <ul>
+ * <li>Status.CREATED (201) if the resource has been created,</li>
+ * <li>Status.CONFLICT if the resource already exists,</li>
+ * <li>Status.INTERNAL_SERVER_ERROR (500) if something went wrong</li>
+ * </ul>
+ */
+ protected ResourceCreationResult createComponentInstance(TOSCAComponentId tcId) {
+ return BackendUtils.create(tcId);
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Class<? extends AbstractComponentInstanceResource> getComponentInstanceResourceClassForType(String type) {
+ // Guess the package
+ String pkg = "org.eclipse.winery.repository.resources.";
+
+ pkg += Utils.getIntermediateLocationStringForType(type, ".");
+
+ // naming convention: Instance is named after container, but without the
+ // plural s
+ String className = pkg + "." + type + "Resource";
+ try {
+ return (Class<? extends AbstractComponentInstanceResource>) Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException("Could not find id class for component instance", e);
+ }
+ }
+
+ /**
+ *
+ * @param namespace encoded namespace
+ * @param id encoded id
+ * @return an instance of the requested resource
+ */
+ @Path("{namespace}/{id}/")
+ public R getComponentInstaceResource(@PathParam("namespace") String namespace, @PathParam("id") String id) {
+ return this.getComponentInstaceResource(namespace, id, true);
+ }
+
+ /**
+ * @param encoded specifies whether namespace and id are encoded
+ * @return an instance of the requested resource
+ */
+ @SuppressWarnings("unchecked")
+ public R getComponentInstaceResource(String namespace, String id, boolean encoded) {
+ TOSCAComponentId tcId;
+ try {
+ tcId = this.getTOSCAcomponentId(namespace, id, encoded);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not create id instance", e);
+ }
+ return (R) AbstractComponentsResource.getComponentInstaceResource(tcId);
+ }
+
+ /**
+ * @return an instance of the requested resource
+ */
+ public AbstractComponentInstanceResource getComponentInstaceResource(QName qname) {
+ return this.getComponentInstaceResource(qname.getNamespaceURI(), qname.getLocalPart(), false);
+ }
+
+ /**
+ * @return an instance of the requested resource
+ * @throws NotFoundException if resource doesn't exist.
+ */
+ public static AbstractComponentInstanceResource getComponentInstaceResource(TOSCAComponentId tcId) {
+ String type = Util.getTypeForComponentId(tcId.getClass());
+ if (!Repository.INSTANCE.exists(tcId)) {
+ AbstractComponentsResource.logger.debug("TOSCA component id " + tcId.toString() + " not found");
+ throw new NotFoundException("TOSCA component id " + tcId.toString() + " not found");
+ }
+ Class<? extends AbstractComponentInstanceResource> newResource = AbstractComponentsResource.getComponentInstanceResourceClassForType(type);
+ Constructor<?>[] constructors = newResource.getConstructors();
+ assert (constructors.length == 1);
+ AbstractComponentInstanceResource newInstance;
+ try {
+ newInstance = (AbstractComponentInstanceResource) constructors[0].newInstance(tcId);
+ } catch (InstantiationException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ AbstractComponentsResource.logger.error("Could not instantiate sub resource " + tcId);
+ throw new IllegalStateException("Could not instantiate sub resource", e);
+ }
+ return newInstance;
+ }
+
+ /**
+ * Returns resources for all known component instances
+ *
+ * Required by topologytemplateedit.jsp
+ */
+ public Collection<AbstractComponentInstanceResource> getAll() {
+ Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass());
+ SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(idClass);
+ ArrayList<AbstractComponentInstanceResource> res = new ArrayList<AbstractComponentInstanceResource>(allTOSCAcomponentIds.size());
+ for (TOSCAComponentId id : allTOSCAcomponentIds) {
+ AbstractComponentInstanceResource r = AbstractComponentsResource.getComponentInstaceResource(id);
+ res.add(r);
+ }
+ return res;
+ }
+
+ /**
+ * Used by org.eclipse.winery.repository.repository.client and by the
+ * artifactcreationdialog.tag. Especially the "name" field is used there at
+ * the UI
+ *
+ * @return A list of all ids of all instances of this component type. If the
+ * "name" attribute is required, that name is used as id <br />
+ * Format:
+ * <code>[({"namespace": "<namespace>", "id": "<id>"},)* ]</code>. A
+ * <code>name<code> field is added if the model allows an additional name attribute
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public String getListOfAllIds() {
+ Class<? extends TOSCAComponentId> idClass = Utils.getComponentIdClassForComponentContainer(this.getClass());
+ boolean supportsNameAttribute = Util.instanceSupportsNameAttribute(idClass);
+ SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(idClass);
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter sw = new StringWriter();
+
+ try {
+ JsonGenerator jg = jsonFactory.createGenerator(sw);
+ // We produce org.eclipse.winery.repository.client.WineryRepositoryClient.NamespaceAndId by hand here
+ // Refactoring could move this class to common and fill it here
+ jg.writeStartArray();
+ for (TOSCAComponentId id : allTOSCAcomponentIds) {
+ jg.writeStartObject();
+ jg.writeStringField("namespace", id.getNamespace().getDecoded());
+ jg.writeStringField("id", id.getXmlId().getDecoded());
+ if (supportsNameAttribute) {
+ AbstractComponentInstanceResource componentInstaceResource = AbstractComponentsResource.getComponentInstaceResource(id);
+ String name = ((IHasName) componentInstaceResource).getName();
+ jg.writeStringField("name", name);
+ }
+ jg.writeEndObject();
+ }
+ jg.writeEndArray();
+ jg.close();
+ } catch (Exception e) {
+ AbstractComponentsResource.logger.error(e.getMessage(), e);
+ return "[]";
+ }
+ return sw.toString();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java
new file mode 100644
index 0000000..33bc1d4
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/AbstractComponentsWithTypeReferenceResource.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.repository.backend.ResourceCreationResult;
+import org.restdoc.annotations.RestDocParam;
+
+/**
+ * This class does NOT inherit from TEntityTemplatesResource<ArtifactTemplate>
+ * as these templates are directly nested in a TDefinitionsElement
+ */
+public abstract class AbstractComponentsWithTypeReferenceResource<T extends AbstractComponentInstanceResource> extends AbstractComponentsResource<T> {
+
+ /**
+ * Creates the resource and sets the specified type
+ *
+ * In contrast to the other component instances in this package, we
+ * additionally need the parameter "type" to set the type of the artifact
+ * template.
+ *
+ * @param namespace Namespace of the template
+ * @param name name attribute of the template
+ * @param type: QName of the type, format: {namespace}localname is retrieved
+ * from namespace manager
+ *
+ * @return URI of the created Resource, null if resource already exists,
+ * URI_internalServerError if an internal server error occurred
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_PLAIN)
+ @Override
+ public Response onPost(@RestDocParam(description = "Namespace of the component") @FormParam("namespace") String namespace, @RestDocParam(description = "name attribute of the component") @FormParam("name") String name, @RestDocParam(description = "QName of the type, format: {namespace}localname") @FormParam("type") String type) {
+ // only check for type parameter as namespace and name are checked in super.onPost
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ ResourceCreationResult creationResult = super.onPost(namespace, name);
+ if (!creationResult.isSuccess()) {
+ return creationResult.getResponse();
+ }
+ if (creationResult.getStatus().equals(Status.CREATED)) {
+ IHasTypeReference resource = (IHasTypeReference) AbstractComponentsResource.getComponentInstaceResource((TOSCAComponentId) creationResult.getId());
+ resource.setType(type);
+ // we assume that setType succeeded and just return the result of the
+ // creation of the artifact template resource
+ // Thus, we do NOT change res
+ }
+ return creationResult.getResponse();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java
new file mode 100644
index 0000000..b9eb345
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintResource.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TConstraint;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+
+public class ConstraintResource extends EntityWithoutIdResource<TConstraint> {
+
+ /**
+ *
+ * @param constraint the current constraint value
+ * @param list the list this constraint belongs to
+ * @param res the node type resource this constraint belongs to. Required
+ * for saving
+ */
+ public ConstraintResource(TConstraint constraint, int idx, List<TConstraint> list, NodeTypeResource res) {
+ super(constraint, idx, list, res);
+ }
+
+ /**
+ * Required for collectionResource
+ *
+ * @throws ClassCastException of !(res instanceof NodeTypeResource)
+ */
+ public ConstraintResource(TConstraint constraint, int idx, List<TConstraint> list, AbstractComponentInstanceResource res) {
+ this(constraint, idx, list, (NodeTypeResource) res);
+ }
+
+ private TConstraint getConstraint() {
+ return this.o;
+ }
+
+ @GET
+ @Path("type")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getConstraintType() {
+ return this.getConstraint().getConstraintType();
+ }
+
+ @PUT
+ @Path("type")
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response putConstraintType(String constraintType) {
+ this.getConstraint().setConstraintType(constraintType);
+ return BackendUtils.persist(this.res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java
new file mode 100644
index 0000000..8aea92f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/ConstraintsResource.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TConstraint;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class ConstraintsResource extends EntityWithoutIdCollectionResource<ConstraintResource, TConstraint> {
+
+ private static final Logger logger = LoggerFactory.getLogger(ConstraintsResource.class);
+
+
+ public ConstraintsResource(List<TConstraint> constraints, NodeTypeResource res) {
+ super(ConstraintResource.class, TConstraint.class, constraints, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ // TODO Auto-generated method stub
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java
new file mode 100644
index 0000000..1b70d56
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/EntityTypeResource.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.util.Collection;
+import java.util.SortedSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.datatypes.select2.Select2DataWithOptGroups;
+import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup;
+import org.eclipse.winery.repository.resources.entitytypes.properties.PropertiesDefinitionResource;
+
+public abstract class EntityTypeResource extends AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal {
+
+ protected EntityTypeResource(TOSCAComponentId id) {
+ super(id);
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ TEntityType entityType = this.getEntityType();
+ entityType.setTargetNamespace(this.getId().getNamespace().getDecoded());
+ entityType.setName(this.getId().getXmlId().getDecoded());
+ }
+
+ /**
+ * Convenience method to avoid casting. Required by
+ * PropertiesDefinitionResource's jsp
+ */
+ public TEntityType getEntityType() {
+ return (TEntityType) this.element;
+ }
+
+ /**
+ * Models PropertiesDefinition
+ */
+ @Path("propertiesdefinition/")
+ public PropertiesDefinitionResource getPropertiesDefinitionResource() {
+ return new PropertiesDefinitionResource(this);
+ }
+
+ /**
+ * Used by children to implement getListOfAllInstances()
+ */
+ protected SortedSet<Select2OptGroup> getListOfAllInstances(Class<? extends TOSCAComponentId> clazz) {
+ Select2DataWithOptGroups data = new Select2DataWithOptGroups();
+
+ Collection<? extends TOSCAComponentId> instanceIds = BackendUtils.getAllElementsRelatedWithATypeAttribute(clazz, this.id.getQName());
+
+ for (TOSCAComponentId instanceId : instanceIds) {
+ String groupText = instanceId.getNamespace().getDecoded();
+ String text = BackendUtils.getName(instanceId);
+ data.add(groupText, instanceId.getQName().toString(), text);
+ }
+
+ return data.asSortedSet();
+ }
+
+ /**
+ * Returns an array suitable for processing in a {@code select2} field See
+ * {@link http://ivaynberg.github.io/select2}
+ *
+ * Each element: {id: "{ns}localname", text: "name/id"}
+ */
+ @Path("instances/")
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public SortedSet<Select2OptGroup> getListOfAllInstances() {
+ Response res = Response.status(Status.INTERNAL_SERVER_ERROR).entity("not yet implemented").build();
+ throw new WebApplicationException(res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java
new file mode 100644
index 0000000..a2a8533
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericComponentPageData.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.SortedSet;
+
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource;
+import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplatesResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationsResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationsResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class GenericComponentPageData {
+
+ private static final Logger logger = LoggerFactory.getLogger(GenericComponentPageData.class);
+
+ private final SortedSet<? extends TOSCAComponentId> componentInstanceIds;
+
+ private final Class<? extends AbstractComponentsResource> resourceClass;
+
+
+ public GenericComponentPageData(Class<? extends AbstractComponentsResource> resourceClass) {
+ this.resourceClass = resourceClass;
+ Class<? extends TOSCAComponentId> cIdClass = Utils.getComponentIdClassForComponentContainer(resourceClass);
+ this.componentInstanceIds = Repository.INSTANCE.getAllTOSCAComponentIds(cIdClass);
+ }
+
+ /**
+ * Outputs the data for GenericComponentPage (Name / Id / Namespace) needed
+ * for the genericcomponentpage.jsp
+ */
+ public SortedSet<? extends TOSCAComponentId> getComponentInstanceIds() {
+ return this.componentInstanceIds;
+ }
+
+ public String getType() {
+ return Utils.getTypeForComponentContainer(this.resourceClass);
+ }
+
+ public String getCSSclass() {
+ // The resources do NOT know their CSS class
+ // Layout is far away from a resource
+ // Instead of a huge if/else-cascade, we derive the CSS name from the
+ // class name
+ String type = this.getType();
+ // convention: first letter in small letters
+ String res = type.substring(0, 1).toLowerCase() + type.substring(1);
+ // this generated "xSDImport" as CSS class for XSDImport
+ return res;
+ }
+
+ public String getLabel() {
+ String type = this.getType();
+ // E.g., convert ArtifactTemplate to Artifact Template
+ String res = type.replaceAll("(\\p{Lower})(\\p{Upper})", "$1 $2");
+ return res;
+ }
+
+ /**
+ * Required for genericcomponentpage.jsp -> addComponentInstance.jsp
+ *
+ * May only be used if the component supports the type (e.g., artifact
+ * templates)
+ *
+ * @return the list of all known <em>types</em>
+ */
+ public Collection<? extends TOSCAComponentId> getTypeSelectorData() {
+ Class<? extends TOSCAComponentId> typeIdClass;
+ if (this.resourceClass.equals(ArtifactTemplatesResource.class)) {
+ typeIdClass = ArtifactTypeId.class;
+ } else if (this.resourceClass.equals(NodeTypeImplementationsResource.class)) {
+ typeIdClass = NodeTypeId.class;
+ } else if (this.resourceClass.equals(RelationshipTypeImplementationsResource.class)) {
+ typeIdClass = RelationshipTypeId.class;
+ } else if (this.resourceClass.equals(PolicyTemplatesResource.class)) {
+ typeIdClass = PolicyTypeId.class;
+ } else {
+ return Collections.emptyList();
+ }
+ SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(typeIdClass);
+ return allTOSCAcomponentIds;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java
new file mode 100644
index 0000000..51bbcf1
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/GenericVisualAppearanceResource.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.elements.TOSCAElementId;
+import org.eclipse.winery.repository.Prefs;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.constants.Filename;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource;
+
+//import com.fasterxml.jackson.annotation.JsonIgnore; // currently not required
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+/**
+ * Contains methods for both visual appearance for
+ * <ul>
+ * <li>node types</li>
+ * <li>relationship types</li>
+ * </ul>
+ */
+public abstract class GenericVisualAppearanceResource {
+
+ protected final Map<QName, String> otherAttributes;
+ protected final TopologyGraphElementEntityTypeResource res;
+ protected final TOSCAElementId id;
+
+
+ @DELETE
+ public Response onDelete() {
+ return BackendUtils.delete(this.id);
+ }
+
+ /**
+ * Used for GUI when accessing the resource as data E.g., for topology
+ * template
+ */
+ //@JsonIgnore
+ public URI getAbsoluteURL() {
+ String URI = Prefs.INSTANCE.getResourcePath();
+ URI = URI + "/" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(this.id));
+ return Utils.createURI(URI);
+ }
+
+ //@JsonIgnore
+ public TOSCAElementId getId() {
+ return this.id;
+ }
+
+ /**
+ * @param res
+ * @param otherAttributes the other attributes of the node/relationship type
+ * @param id the id of this subresource required for storing the images
+ */
+ public GenericVisualAppearanceResource(TopologyGraphElementEntityTypeResource res, Map<QName, String> otherAttributes, VisualAppearanceId id) {
+ this.id = id;
+ this.res = res;
+ this.otherAttributes = otherAttributes;
+ }
+
+ /**
+ * Determines repository reference to file in repo
+ */
+ protected RepositoryFileReference getRepoFileRef(String name) {
+ return new RepositoryFileReference(this.id, name);
+ }
+
+ protected Response getImage(String name, String modified) {
+ RepositoryFileReference target = this.getRepoFileRef(name);
+ return BackendUtils.returnRepoPath(target, modified);
+ }
+
+ /**
+ * Arbitrary images are supported. There currently is no check for valid
+ * image media types
+ */
+ protected Response putImage(String name, InputStream uploadedInputStream, MediaType mediaType) {
+ RepositoryFileReference target = this.getRepoFileRef(name);
+ return BackendUtils.putContentToFile(target, uploadedInputStream, mediaType);
+ }
+
+ @GET
+ @Path("16x16")
+ public Response get16x16Image(@HeaderParam("If-Modified-Since") String modified) {
+ // Even if the extension is "png", it might contain a jpg, too
+ // We keep the file extension as the windows explorer can display previews even if the content is not a png
+ return this.getImage(Filename.FILENAME_SMALL_ICON, modified);
+ }
+
+ @PUT
+ @Path("16x16")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response post16x16Image(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) {
+ return this.putImage(Filename.FILENAME_SMALL_ICON, uploadedInputStream, body.getMediaType());
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java
new file mode 100644
index 0000000..08a3696
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasName.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.restdoc.annotations.RestDoc;
+
+/**
+ * Ensures that the AbstractComponentInstance has a getName method
+ */
+public interface IHasName {
+
+ @GET
+ @Path("name")
+ // @formatter:off
+ @RestDoc(methodDescription = "Returns the name of the element. " +
+ "Defaults to the ID of the element. " +
+ "Some other ComponentInstances either carry a name or an ID. ")
+ // @formatter:on
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getName();
+
+ @PUT
+ @Path("name")
+ public Response setName(@FormParam("value") String name);
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java
new file mode 100644
index 0000000..cb42158
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/IHasTypeReference.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+public interface IHasTypeReference {
+
+ /**
+ * @return the QName of the type with full namespace, never null (according
+ * to spec)
+ */
+ public QName getType();
+
+ /**
+ * Sets the type and directly persists the resource
+ */
+ public Response setType(QName type);
+
+ /**
+ * Calls setType(QName) with QName.valueOf(typeStr)
+ *
+ * Directly persists the resource
+ *
+ * @param typeStr a textual representation of a QName
+ */
+ public Response setType(String typeStr);
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java
new file mode 100644
index 0000000..c8438ef
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResource.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+/**
+ * Implementors can have DAs attached
+ */
+public interface INodeTemplateResourceOrNodeTypeImplementationResource extends INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java
new file mode 100644
index 0000000..7bd178e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import org.eclipse.winery.common.ids.Namespace;
+
+/**
+ * Implementors can have IAs or DAs attached
+ */
+public interface INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource {
+
+ Namespace getNamespace();
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java
new file mode 100644
index 0000000..892a7cb
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/INodeTypeImplementationResourceOrRelationshipTypeImplementationResource.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+/**
+ * Implementors can have IAs attached
+ */
+public interface INodeTypeImplementationResourceOrRelationshipTypeImplementationResource extends INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java
new file mode 100644
index 0000000..7cc878a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/InheritanceResource.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.repository.backend.Repository;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Class for managing inheritance properties: abstract, final, derivedFromn
+ *
+ * The linking in the resources tree is different than the others. Here, there
+ * is no additional Id generated.
+ *
+ * We separated the code here to have the collection of valid super types in a
+ * separate class. We think, this is less confusing than including this
+ * functionality in
+ * AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinalDefinitionsBacked
+ */
+public class InheritanceResource {
+
+ private AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal managedResource;
+
+
+ public InheritanceResource(AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal res) {
+ this.managedResource = res;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/inheritance.jsp", this);
+ }
+
+ public String getIsAbstract() {
+ return this.managedResource.getIsAbstract();
+ }
+
+ public String getIsFinal() {
+ return this.managedResource.getIsAbstract();
+ }
+
+ public String getDerivedFrom() {
+ return this.managedResource.getDerivedFrom();
+ }
+
+ /** JSP Data **/
+
+ public SortedSet<? extends TOSCAComponentId> getPossibleSuperTypes() {
+ // sorted by Name, not by namespace
+ SortedSet<? extends TOSCAComponentId> allTOSCAcomponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(this.managedResource.getId().getClass());
+ SortedSet<? extends TOSCAComponentId> res = new TreeSet<>(allTOSCAcomponentIds);
+ res.remove(this.managedResource.getId());
+ // FEATURE: Possibly exclude all subtypes to avoid circles. However, this could be disappointing for users who know what they are doing
+ return res;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java
new file mode 100644
index 0000000..87b5275
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/MainResource.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.importing.CSARImporter;
+import org.eclipse.winery.repository.resources.API.APIResource;
+import org.eclipse.winery.repository.resources.admin.AdminTopResource;
+import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplatesResource;
+import org.eclipse.winery.repository.resources.entitytemplates.policytemplates.PolicyTemplatesResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationsResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationsResource;
+import org.eclipse.winery.repository.resources.entitytypes.artifacttypes.ArtifactTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.capabilitytypes.CapabilityTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.policytypes.PolicyTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.requirementtypes.RequirementTypesResource;
+import org.eclipse.winery.repository.resources.imports.ImportsResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplatesResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.restdoc.annotations.RestDocReturnCode;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataParam;
+
+/**
+ * All paths listed here have to be listed in Jersey's filter configuration
+ */
+@Path("/")
+public class MainResource {
+
+ @Path("API/")
+ public APIResource api() {
+ return new APIResource();
+ }
+
+ @Path("artifacttemplates/")
+ public ArtifactTemplatesResource artifacttemplates() {
+ return new ArtifactTemplatesResource();
+ }
+
+ @Path("artifacttypes/")
+ public ArtifactTypesResource artifactypes() {
+ return new ArtifactTypesResource();
+ }
+
+ @Path("admin/")
+ public AdminTopResource admin() {
+ return new AdminTopResource();
+ }
+
+ @Path("capabilitytypes/")
+ public CapabilityTypesResource capabilitytypes() {
+ return new CapabilityTypesResource();
+ }
+
+ @Path("imports/")
+ public ImportsResource imports() {
+ return new ImportsResource();
+ }
+
+ @Path("nodetypes/")
+ public NodeTypesResource nodetypes() {
+ return new NodeTypesResource();
+ }
+
+ @Path("nodetypeimplementations/")
+ public NodeTypeImplementationsResource nodetypeimplementations() {
+ return new NodeTypeImplementationsResource();
+ }
+
+ @Path("other/")
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getOtherElements() {
+ return new Viewable("/jsp/otherElements.jsp");
+ }
+
+ @Path("policytemplates/")
+ public PolicyTemplatesResource policytemplates() {
+ return new PolicyTemplatesResource();
+ }
+
+ @Path("policytypes/")
+ public PolicyTypesResource policytypes() {
+ return new PolicyTypesResource();
+ }
+
+ @Path("relationshiptypes/")
+ public RelationshipTypesResource relationshiptypes() {
+ return new RelationshipTypesResource();
+ }
+
+ @Path("requirementtypes/")
+ public RequirementTypesResource requirementtypes() {
+ return new RequirementTypesResource();
+ }
+
+ @Path("relationshiptypeimplementations/")
+ public RelationshipTypeImplementationsResource relationshiptypeimplementations() {
+ return new RelationshipTypeImplementationsResource();
+ }
+
+ @Path("servicetemplates/")
+ public ServiceTemplatesResource servicetemplates() {
+ return new ServiceTemplatesResource();
+ }
+
+ /**
+ * Returns the main page of winery.
+ */
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response onGet() {
+ return Response.temporaryRedirect(Utils.createURI("servicetemplates/")).build();
+ }
+
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ @RestDoc(methodDescription = "Imports the given CSAR (sent by simplesinglefileupload.jsp)")
+ @RestDocReturnCode(code = "200", description = "If the CSAR could be partially imported, the points where it failed are returned in the body")
+ // @formatter:off
+ public Response importCSAR(
+ @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail,
+ @FormDataParam("overwrite") @RestDocParam(description = "true: content of CSAR overwrites existing content. false (default): existing content is kept") Boolean overwrite) {
+ // @formatter:on
+ CSARImporter importer = new CSARImporter();
+ List<String> errors = new ArrayList<String>();
+ boolean ow;
+ ow = (overwrite != null) && overwrite;
+ try {
+ importer.readCSAR(uploadedInputStream, errors, ow, true);
+ } catch (Exception e) {
+ return Response.serverError().entity("Could not import CSAR").entity(e.getMessage()).build();
+ }
+ if (errors.isEmpty()) {
+ return Response.noContent().build();
+ } else {
+ // In case there are errors, we send them as "bad request"
+ return Response.status(Status.BAD_REQUEST).entity(errors).build();
+ }
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_XML)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response importDefinitions(InputStream is) throws IOException {
+ File toscaFile;
+ toscaFile = File.createTempFile("TOSCA", ".tosca");
+ FileUtils.copyInputStreamToFile(is, toscaFile);
+ CSARImporter importer = new CSARImporter();
+ List<String> errors = new ArrayList<>();
+ importer.importDefinitions(null, toscaFile.toPath(), errors, false, true);
+ if (errors.isEmpty()) {
+ return Response.noContent().build();
+ } else {
+ return Response.status(Status.BAD_REQUEST).entity(errors).build();
+ }
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java
new file mode 100644
index 0000000..3f79c87
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/SubMenuData.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources;
+
+/**
+ * Data used to render a submenu item
+ */
+public class SubMenuData {
+
+ private final String href;
+ private final String text;
+
+ public static final SubMenuData SUBMENU_DOCUMENTATION = new SubMenuData("#documentation", "Documentation");
+ public static final SubMenuData SUBMENU_XML = new SubMenuData("#xml", "XML");
+
+
+ public SubMenuData(String href, String text) {
+ this.href = href;
+ this.text = text;
+ }
+
+ public String getHref() {
+ return this.href;
+ }
+
+ public String getText() {
+ return this.text;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java
new file mode 100644
index 0000000..85f565c
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/IPersistable.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support;
+
+import java.io.IOException;
+
+public interface IPersistable {
+
+ /**
+ * @throws IOException if content could not be updated in the repository
+ * @throws IllegalStateException if an JAXBException occurred. This should
+ * never happen.
+ */
+ public void persist() throws IOException;
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java
new file mode 100644
index 0000000..f150855
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/CollectionsHelper.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections;
+
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+
+public class CollectionsHelper {
+
+ private CollectionsHelper() {
+ }
+
+ /**
+ *
+ * @param <X>
+ * @param resource the resource to be persisted
+ * @param idDetermination the object to use to determine the id of the
+ * entity
+ * @param entity the entity that was persisted. Used to determine the id
+ * @return the new id id of the resource
+ */
+ public static <X> Response persist(IPersistable resource, IIdDetermination<X> idDetermination, X entity) {
+ Response res = BackendUtils.persist(resource);
+ if (res.getStatus() == 204) {
+ String id = idDetermination.getId(entity);
+ res = Response.ok(id).build();
+ }
+ return res;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java
new file mode 100644
index 0000000..64d0fbe
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityCollectionResource.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.datatypes.select2.Select2DataItem;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.restdoc.annotations.RestDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.NotFoundException;
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Class managing a list of entities. It is intended to manage subresources,
+ * which are stored in a list. Either all entities have a unique key given by
+ * the TOSCA specification (subclass EntityWithIdCollectionResource) or a unique
+ * key is generated (subclass EntityWithoutIdCollectionResource)
+ *
+ * @param <EntityResourceT> the resource modeling the entity
+ * @param <EntityT> the entity type of single items in the list
+ */
+public abstract class EntityCollectionResource<EntityResourceT extends EntityResource<EntityT>, EntityT> implements IIdDetermination<EntityT> {
+
+ private static final Logger logger = LoggerFactory.getLogger(EntityCollectionResource.class);
+
+ protected final List<EntityT> list;
+
+ protected final IPersistable res;
+
+ protected final Class<EntityT> entityTClazz;
+
+ protected final Class<EntityResourceT> entityResourceTClazz;
+
+
+ /**
+ * @param clazz the class of EntityT. Required as it is not possible to call
+ * new EntityT (see http://stackoverflow.com/a/1090488/873282)
+ * @param list the list of entities contained in this resource. Has to be
+ * typed <Object> as not all TOSCA elements in the specification
+ * inherit from TExtensibleElements
+ * @param res the main resource the list is belonging to. Required for
+ * persistence.
+ */
+ public EntityCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) {
+ this.entityResourceTClazz = entityResourceTClazz;
+ this.entityTClazz = entityTClazz;
+ this.list = list;
+ this.res = res;
+ }
+
+ /**
+ * Returns a list of ids of all entities nested here
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Object getListOfAllEntityIds(@QueryParam("select2") String select2) {
+ if (select2 == null) {
+ return this.getListOfAllEntityIdsAsList();
+ } else {
+ // return data ready for consumption by select2
+ List<Select2DataItem> res = new ArrayList<Select2DataItem>(this.list.size());
+ for (EntityT o : this.list) {
+ String id = this.getId(o);
+ Select2DataItem di = new Select2DataItem(id, id);
+ res.add(di);
+ }
+ return res;
+ }
+ }
+
+ public List<String> getListOfAllEntityIdsAsList() {
+ List<String> res = new ArrayList<String>(this.list.size());
+ for (EntityT o : this.list) {
+ // We assume that different Object serializations *always* have different hashCodes
+ res.add(this.getId(o));
+ }
+ return res;
+ }
+
+ /**
+ * Required by reqandcapdefs.jsp
+ */
+ public List<EntityResourceT> getAllEntityResources() {
+ List<String> listOfAllSubResources = this.getListOfAllEntityIdsAsList();
+ List<EntityResourceT> res = new ArrayList<EntityResourceT>(listOfAllSubResources.size());
+ for (String id : listOfAllSubResources) {
+ res.add(this.getEntityResourceFromDecodedId(id));
+ }
+ return res;
+ }
+
+ public EntityResourceT getEntityResourceFromDecodedId(String id) {
+ EntityT entity = null;
+ int idx = -1;
+ for (EntityT c : this.list) {
+ idx++;
+ String cId = this.getId(c);
+ if (cId.equals(id)) {
+ entity = c;
+ break;
+ }
+ }
+ if (entity == null) {
+ throw new NotFoundException();
+ } else {
+ return this.getEntityResourceInstance(entity, idx);
+ }
+ }
+
+ @Path("{id}/")
+ public EntityResourceT getEntityResource(@PathParam("id") String id) {
+ if (id == null) {
+ throw new IllegalArgumentException("id has to be given");
+ }
+ id = Util.URLdecode(id);
+ return this.getEntityResourceFromDecodedId(id);
+ }
+
+ /**
+ * @param entity the entity to create a resource for
+ * @param idx the index in the list
+ * @return the resource managing the given entity
+ */
+ protected abstract EntityResourceT getEntityResourceInstance(EntityT entity, int idx);
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ @RestDoc(methodDescription = "@return the HTML fragment (DIV-container) to be embedded in the 'Interface' part of nodetype.js ")
+ public Response getHTMLAsResponse() {
+ Viewable viewable = this.getHTML();
+ return Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build();
+ }
+
+ /**
+ * called by getHTMLAsResponse
+ */
+ public abstract Viewable getHTML();
+
+ /**
+ * Adds a new entity
+ *
+ * In case the element already exists, we return "CONFLICT"
+ */
+ @POST
+ @Consumes({MediaType.TEXT_XML, MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
+ public Response addNewElement(EntityT entity) {
+ if (entity == null) {
+ return Response.status(Status.BAD_REQUEST).entity("a valid XML/JSON element has to be posted").build();
+ }
+ if (this.alreadyContains(entity)) {
+ // we do not replace the element, but replace it
+ return Response.status(Status.CONFLICT).build();
+ }
+ this.list.add(entity);
+ return CollectionsHelper.persist(this.res, this, entity);
+ }
+
+ @Override
+ public abstract String getId(EntityT entity);
+
+ /**
+ * Checks for containment of e in the list. <code>equals</code> is not used
+ * as most EntityT do not offer a valid implementation
+ *
+ * @return true if list already contains e.
+ */
+ public boolean alreadyContains(EntityT e) {
+ String id = this.getId(e);
+ for (EntityT el : this.list) {
+ if (this.getId(el).equals(id)) {
+ // break loop
+ // we found an equal list item
+ return true;
+ }
+ }
+ // all items checked: nothing equal contained
+ return false;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java
new file mode 100644
index 0000000..361fcfb
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/EntityResource.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+
+/**
+ * Class to hold a single entity residing in a list of entities
+ *
+ * @param <EntityT> the entity type contained in the list
+ */
+public abstract class EntityResource<EntityT> {
+
+ // This is non-final as a "PUT" may update the object
+ // it might be unnecessary to update this object as the resource is created at each request
+ // We update the reference nevertheless to be safe if the resource is used in another context
+ protected EntityT o;
+
+ protected final int idx;
+
+ protected final List<EntityT> list;
+
+ protected final IPersistable res;
+
+ protected IIdDetermination<EntityT> idDetermination;
+
+
+ /**
+ *
+ * @param idDetermination the object offering determination of an id of
+ * EntityT. May be null. If null, then setIdDetermination(obj)
+ * has to be called to enable this class functioning properly
+ * @param o the object this resource is representing
+ * @param idx the index of the object in the list
+ * @param list the list, where the object is stored in
+ * @param res the resource the object/list belongs to
+ */
+ public EntityResource(IIdDetermination<EntityT> idDetermination, EntityT o, int idx, List<EntityT> list, IPersistable res) {
+ this.idDetermination = idDetermination;
+ this.o = o;
+ this.idx = idx;
+ this.list = list;
+ this.res = res;
+ }
+
+ /**
+ * Quick hack for AbstractReqOrCapDefResource which is itself an
+ * IIdDetermination
+ */
+ protected final void setIdDetermination(IIdDetermination<EntityT> idDetermination) {
+ this.idDetermination = idDetermination;
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getJSON() {
+ assert (this.o != null);
+ return Response.ok().entity(this.o).build();
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_XML)
+ @SuppressWarnings("unchecked")
+ public Response getXML() {
+ assert (this.o != null);
+ // Utils.getXML has to be used as Jersey can only serialize XMLRootElements
+ return Utils.getXML((Class<EntityT>) this.o.getClass(), this.o);
+ }
+
+ /**
+ * Replaces the whole entity by the given entity
+ *
+ * As we use the hash code as index, the index changes when the resource is
+ * updated. This is not in line with REST. The alternative implementation is
+ * to use the index in the list as resource identification. That changes at
+ * each modification of the list itself (if elements are deleted / inserted
+ * before the current entry). When using the hash value, users may
+ * concurrently edit items and the list may also be updated
+ *
+ * @return the new id.
+ */
+ @PUT
+ @Consumes(MediaType.TEXT_XML)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response setValue(EntityT o) {
+ this.list.set(this.idx, o);
+ this.o = o;
+ return CollectionsHelper.persist(this.res, this.idDetermination, o);
+ }
+
+ @DELETE
+ public Response onDelete() {
+ try {
+ this.list.remove(this.idx);
+ } catch (IndexOutOfBoundsException e) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not delete entity, even if it should exist").build();
+ }
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java
new file mode 100644
index 0000000..e479e70
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/IIdDetermination.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections;
+
+public interface IIdDetermination<EntityT> {
+
+ /**
+ * @return the id of the given entity
+ */
+ public String getId(EntityT e);
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java
new file mode 100644
index 0000000..f428752
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdCollectionResource.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections.withid;
+
+import java.lang.reflect.Constructor;
+import java.util.List;
+
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class EntityWithIdCollectionResource<EntityResourceT extends EntityWithIdResource<EntityT>, EntityT> extends EntityCollectionResource<EntityResourceT, EntityT> {
+
+ private static final Logger logger = LoggerFactory.getLogger(EntityWithIdCollectionResource.class);
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public EntityWithIdCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) {
+ super(entityResourceTClazz, entityTClazz, list, res);
+ }
+
+ /**
+ * Each CollectionResource has to implement the id getting by itself as
+ * TOSCA XSD does not provide a general purpose id fetching mechanism
+ */
+ @Override
+ public abstract String getId(EntityT entity);
+
+ @Override
+ protected EntityResourceT getEntityResourceInstance(EntityT entity, int idx) {
+ Constructor<EntityResourceT> constructor;
+ try {
+ constructor = this.entityResourceTClazz.getConstructor(IIdDetermination.class, this.entityTClazz, int.class, List.class, this.res.getClass());
+ } catch (Exception e) {
+ try {
+ constructor = this.entityResourceTClazz.getConstructor(IIdDetermination.class, this.entityTClazz, int.class, List.class, IPersistable.class);
+ } catch (Exception e2) {
+ EntityWithIdCollectionResource.logger.debug("Could not get constructor", e);
+ EntityWithIdCollectionResource.logger.debug("res.getClass() was {}", this.res.getClass());
+ throw new IllegalStateException(e2);
+ }
+ }
+ EntityResourceT newInstance;
+ try {
+ newInstance = constructor.newInstance(this, entity, idx, this.list, this.res);
+ } catch (Exception e) {
+ EntityWithIdCollectionResource.logger.debug("Could not instantiate class", e);
+ throw new IllegalStateException(e);
+ }
+ return newInstance;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java
new file mode 100644
index 0000000..1ac6775
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withid/EntityWithIdResource.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections.withid;
+
+import java.util.List;
+
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.EntityResource;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+
+public class EntityWithIdResource<EntityT> extends EntityResource<EntityT> {
+
+ /**
+ * {@inheritDoc}
+ */
+ public EntityWithIdResource(IIdDetermination<EntityT> idDetermination, EntityT o, int idx, List<EntityT> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java
new file mode 100644
index 0000000..8255f5d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdCollectionResource.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections.withoutid;
+
+import java.lang.reflect.Constructor;
+import java.util.List;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.NotFoundException;
+
+/**
+ * Class managing a list of entities. It is intended to manage subresources,
+ * where the TOSCA specification did not specify a unique key. Currently, the
+ * hashCode of the XML String representation is used. If other representation
+ * should be used, the method {@code getEntityResource} has to be overriden.
+ *
+ * @param <EntityResourceT> the resource modeling the entity
+ * @param <EntityT> the entity type of single items in the list
+ */
+public abstract class EntityWithoutIdCollectionResource<EntityResourceT extends EntityWithoutIdResource<EntityT>, EntityT> extends EntityCollectionResource<EntityResourceT, EntityT> {
+
+ private static final Logger logger = LoggerFactory.getLogger(EntityWithoutIdCollectionResource.class);
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public EntityWithoutIdCollectionResource(Class<EntityResourceT> entityResourceTClazz, Class<EntityT> entityTClazz, List<EntityT> list, IPersistable res) {
+ super(entityResourceTClazz, entityTClazz, list, res);
+ }
+
+ /**
+ * Method searching the list for an id with the hashcode instead of
+ * getId(EntityT)
+ */
+ @Override
+ @Path("{id}/")
+ public EntityResourceT getEntityResource(@PathParam("id") String id) {
+ id = Util.URLdecode(id);
+ int idInt;
+ try {
+ idInt = Integer.parseInt(id);
+ } catch (java.lang.NumberFormatException e) {
+ throw new NotFoundException(id + " is not a valid id");
+ }
+ EntityT entity = null;
+ int idx = -1;
+ for (EntityT c : this.list) {
+ idx++;
+ // speed optimization - instead of using getId() we directly use the hash code
+ int hash = Utils.getXMLAsString(c).hashCode();
+ if (hash == idInt) {
+ entity = c;
+ break;
+ }
+ }
+ if (entity == null) {
+ throw new NotFoundException();
+ } else {
+ return this.getEntityResourceInstance(entity, idx);
+ }
+ }
+
+ @Override
+ public String getId(EntityT entity) {
+ return IdDeterminationWithHashCode.INSTANCE.getId(entity);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected EntityResourceT getEntityResourceInstance(EntityT entity, int idx) {
+ Constructor<EntityResourceT> constructor;
+ try {
+ constructor = this.entityResourceTClazz.getConstructor(this.entityTClazz, int.class, List.class, AbstractComponentInstanceResource.class);
+ } catch (Exception e) {
+ try {
+ constructor = this.entityResourceTClazz.getConstructor(this.entityTClazz, int.class, List.class, IPersistable.class);
+ } catch (NoSuchMethodException | SecurityException e1) {
+ EntityWithoutIdCollectionResource.logger.debug("Could not get constructor", e);
+ throw new IllegalStateException(e);
+ }
+ }
+ EntityResourceT newInstance;
+ try {
+ newInstance = constructor.newInstance(entity, idx, this.list, this.res);
+ } catch (Exception e) {
+ EntityWithoutIdCollectionResource.logger.debug("Could not instantiate class", e);
+ throw new IllegalStateException(e);
+ }
+ return newInstance;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java
new file mode 100644
index 0000000..0cf2766
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/EntityWithoutIdResource.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections.withoutid;
+
+import java.util.List;
+
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.EntityResource;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+
+/**
+ * {@inheritDoc}
+ */
+public abstract class EntityWithoutIdResource<EntityT> extends EntityResource<EntityT> {
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ public EntityWithoutIdResource(EntityT o, int idx, List<EntityT> list, IPersistable res) {
+ super((IIdDetermination<EntityT>) IdDeterminationWithHashCode.INSTANCE, o, idx, list, res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java
new file mode 100644
index 0000000..6b4e247
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/IdDeterminationWithHashCode.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources._support.collections.withoutid;
+
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+
+public class IdDeterminationWithHashCode implements IIdDetermination<Object> {
+
+ public static final IdDeterminationWithHashCode INSTANCE = new IdDeterminationWithHashCode();
+
+
+ @Override
+ public String getId(Object entity) {
+ // We assume that different Object serializations *always* have different hashCodes
+ int hash = Utils.getXMLAsString(entity).hashCode();
+ return Integer.toString(hash);
+ }
+
+ /**
+ * Static wrapper method for functions.tld
+ */
+ public static String getIdStatically(Object entity) {
+ return IdDeterminationWithHashCode.INSTANCE.getId(entity);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java
new file mode 100644
index 0000000..c62b344
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/_support/collections/withoutid/package-info.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+/**
+ * This package contains abstract resources implementing common functionality to
+ * support collections of entities, where the data model does not provide a
+ * unique id
+ */
+package org.eclipse.winery.repository.resources._support.collections.withoutid; \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java
new file mode 100644
index 0000000..cd4e20e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AbstractAdminResource.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.core.Response;
+
+import org.apache.commons.configuration.Configuration;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.admin.AdminId;
+
+/**
+ * Instance of one admin resource
+ *
+ * Offers a configuration object to store data
+ */
+public abstract class AbstractAdminResource {
+
+ protected final AdminId id;
+ protected Configuration configuration;
+
+
+ /**
+ * @param id the id of the element rendered by this resource
+ */
+ public AbstractAdminResource(AdminId id) {
+ this.id = id;
+ this.configuration = Repository.INSTANCE.getConfiguration(id);
+ }
+
+ @DELETE
+ public Response onDelete() {
+ return BackendUtils.delete(this.id);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java
new file mode 100644
index 0000000..7e4a662
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/AdminTopResource.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager;
+import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager;
+import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class AdminTopResource {
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/admin/adminindex.jsp", this);
+ }
+
+ @Path("namespaces/")
+ public NamespacesResource getNamespacesResource() {
+ return NamespacesResource.INSTANCE;
+ }
+
+ @Path("repository/")
+ public RepositoryAdminResource getRepositoryAdminResource() {
+ return new RepositoryAdminResource();
+ }
+
+ @Path("planlanguages/")
+ public PlanLanguagesManager getPlanLanguagesResource() {
+ return PlanLanguagesManager.INSTANCE;
+ }
+
+ @Path("plantypes/")
+ public PlanTypesManager getPlanTypesResource() {
+ return PlanTypesManager.INSTANCE;
+ }
+
+ @Path("constrainttypes/")
+ public ConstraintTypesManager getConstraintTypesManager() {
+ return ConstraintTypesManager.INSTANCE;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java
new file mode 100644
index 0000000..f8fb9f1
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/NamespacesResource.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.admin.NamespacesId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Manages prefixes for the namespaces
+ */
+public class NamespacesResource extends AbstractAdminResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(NamespacesResource.class);
+
+ public final static NamespacesResource INSTANCE = new NamespacesResource();
+
+ private Integer nsCount = 0;
+
+
+ private NamespacesResource() {
+ super(new NamespacesId());
+
+ // globally set prefixes
+ // if that behavior is not desired, the code has to be moved to "generatePrefix" which checks for existence, ...
+ this.configuration.setProperty("http://www.w3.org/2001/XMLSchema", "xsd");
+ this.configuration.setProperty("http://www.w3.org/XML/1998/namespace", "xmlns");
+ this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_NAMESPACE, "tosca");
+ this.configuration.setProperty(org.eclipse.winery.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "winery");
+ }
+
+ private Collection<String> getAllPrefixes() {
+ Iterator<String> keys = this.configuration.getKeys();
+ HashSet<String> res = new HashSet<String>();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ String prefix = this.configuration.getString(key);
+ res.add(prefix);
+ }
+ return res;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML() {
+ Viewable viewable = new Viewable("/jsp/admin/namespaces.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+
+ /**
+ * Sets / overwrites prefix/namespace mapping
+ *
+ * In case the prefix is already bound to another namespace, BAD_REQUEST is
+ * returned.
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response addNamespace(@FormParam("namespace") String namespace, @FormParam("nsPrefix") String prefix) {
+ if (StringUtils.isEmpty(namespace)) {
+ return Response.status(Status.BAD_REQUEST).entity("namespace must be given.").build();
+ }
+ if (StringUtils.isEmpty(prefix)) {
+ return Response.status(Status.BAD_REQUEST).entity("prefix must be given.").build();
+ }
+ namespace = Util.URLdecode(namespace);
+ prefix = Util.URLdecode(prefix);
+ Collection<String> allPrefixes = this.getAllPrefixes();
+ if (allPrefixes.contains(prefix)) {
+ if (NamespacesResource.getPrefix(namespace).equals(prefix)) {
+ return Response.notModified().build();
+ } else {
+ // the requested prefix is already bound to a different namespace
+ return Response.status(Status.BAD_REQUEST).entity("prefix already bound to a different namespace.").build();
+ }
+ }
+ this.configuration.setProperty(namespace, prefix);
+ return Response.noContent().build();
+ }
+
+ /**
+ * Deletes given namespace from the repository
+ *
+ * @param URI to delete. The namespace is URLencoded.
+ * @return
+ */
+ @DELETE
+ @Path("{namespace}")
+ public Response onDelete(@PathParam("namespace") String URI) {
+ Response res;
+ URI = Util.URLdecode(URI);
+ if (this.configuration.containsKey(URI)) {
+ this.configuration.clearProperty(URI);
+ res = Response.noContent().build();
+ } else {
+ res = Response.status(Status.NOT_FOUND).build();
+ }
+ return res;
+ }
+
+ /**
+ * SIDEFFECT: URI is added to list of known namespaces if it did not exist
+ * before
+ */
+ public static String getPrefix(Namespace namespace) {
+ String ns = namespace.getDecoded();
+ return NamespacesResource.getPrefix(ns);
+ }
+
+ @Path("{namespace}")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getPrefixForEncodedNamespace(@PathParam("namespace") String URI) {
+ URI = Util.URLdecode(URI);
+ return NamespacesResource.getPrefix(URI);
+ }
+
+ /**
+ * SIDEFFECT: URI is added to list of known namespaces if it did not exist
+ * before
+ */
+ public static String getPrefix(String namespace) {
+ if (namespace == null) {
+ throw new IllegalArgumentException("Namespace must not be null");
+ }
+ String prefix = NamespacesResource.INSTANCE.configuration.getString(namespace);
+ if (prefix == null) {
+ prefix = NamespacesResource.generatePrefix(namespace);
+ NamespacesResource.INSTANCE.configuration.setProperty(namespace, prefix);
+ }
+ return prefix;
+ }
+
+ private static String generatePrefix(String namespace) {
+ String prefix = null;
+ Collection<String> allPrefixes = NamespacesResource.INSTANCE.getAllPrefixes();
+
+ // TODO: generate prefix using URI (and not "arbitrary" prefix)
+ do {
+ prefix = String.format("ns%d", NamespacesResource.INSTANCE.nsCount);
+ NamespacesResource.INSTANCE.nsCount++;
+ } while (allPrefixes.contains(prefix));
+ return prefix;
+ }
+
+ /**
+ * Returns the list of all namespaces registered with his manager. It could
+ * be incomplete, if entries have been added manually to the repository
+ *
+ * @return all namespaces registered with this manager.
+ */
+ private HashSet<Namespace> getRegisteredNamespaces() {
+ HashSet<Namespace> res = new HashSet<Namespace>();
+ Iterator<String> keys = this.configuration.getKeys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ Namespace ns = new Namespace(key, false);
+ res.add(ns);
+ }
+ return res;
+ }
+
+ /**
+ * Returns the list of all namespaces registered with his manager and used
+ * at component instances.
+ */
+ public static Collection<Namespace> getNamespaces() {
+ HashSet<Namespace> res = NamespacesResource.INSTANCE.getRegisteredNamespaces();
+ res.addAll(Repository.INSTANCE.getUsedNamespaces());
+ return res;
+ }
+
+ /**
+ * This method is required because static methods cannot be accessed by EL
+ *
+ * @return see getNamespaces()
+ */
+ public Collection<Namespace> getNamespacesForJSP() {
+ return NamespacesResource.getNamespaces();
+ }
+
+ /**
+ * Returns the list of all namespaces registered with his manager and used
+ * at component instances.
+ *
+ * @return a JSON list containing the non-encoded URIs of each known
+ * namespace
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public String getNamespacesAsJSONlist() {
+ Collection<Namespace> namespaces = NamespacesResource.getNamespaces();
+
+ // We now have all namespaces
+ // We need to convert from Namespace to String
+
+ TreeSet<String> stringNamespaces = new TreeSet<String>();
+ for (Namespace ns : namespaces) {
+ stringNamespaces.add(ns.getDecoded());
+ }
+
+ String res;
+ try {
+ res = Utils.mapper.writeValueAsString(stringNamespaces);
+ } catch (JsonProcessingException e) {
+ NamespacesResource.logger.error(e.getMessage(), e);
+ res = "[]";
+ }
+ return res;
+ }
+
+ /**
+ * Checks whether a prefix is registered for a namespace
+ *
+ * Used at CSARImporter
+ */
+ public boolean getIsPrefixKnownForNamespace(String namespace) {
+ return this.configuration.containsKey(namespace);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java
new file mode 100644
index 0000000..408704d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/RepositoryAdminResource.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+
+import org.eclipse.winery.repository.Prefs;
+import org.eclipse.winery.repository.backend.IRepositoryAdministration;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.filebased.GitBasedRepository;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataParam;
+
+public class RepositoryAdminResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(RepositoryAdminResource.class);
+
+
+ // @formatter:off
+ @GET
+ @Produces(MediaType.TEXT_HTML) // we cannot add MimeTypes.MIMETYPE_ZIP as dumpRepository also produces that mimetype
+ @RestDoc(methodDescription = "Returns the repository admin page and implements administration utility")
+ public Response onGet(
+ @QueryParam(value = "dump") @RestDocParam(description = "If given, a dump of the repository is sent") String dump,
+ @QueryParam(value = "reset") @RestDocParam(description = "Resets the repository to the last &ldquo;official&rdquo; known state") String reset,
+ @QueryParam(value = "commit") @RestDocParam(description = "Commits the current state to the repository and pushes it upstream") String commit
+ ) {
+ // @formatter:on
+ if (dump != null) {
+ return this.dumpRepository();
+ } else if (reset != null) {
+ try {
+ ((GitBasedRepository) Prefs.INSTANCE.getRepository()).cleanAndResetHard();
+ } catch (Exception e) {
+ Response res;
+ res = Response.serverError().entity(e.getMessage()).build();
+ return res;
+ }
+ return Response.noContent().build();
+ } else if (commit != null) {
+ try {
+ ((GitBasedRepository) Prefs.INSTANCE.getRepository()).addCommitPush();
+ } catch (Exception e) {
+ Response res;
+ res = Response.serverError().entity(e.getMessage()).build();
+ return res;
+ }
+ return Response.noContent().build();
+ } else {
+ Viewable viewable = new Viewable("/jsp/admin/repository.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+ }
+
+ /**
+ * Imports the given ZIP
+ */
+ @POST
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response importRepositoryDump(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) {
+ ((IRepositoryAdministration) Repository.INSTANCE).doImport(uploadedInputStream);
+ return Response.noContent().build();
+ }
+
+ @DELETE
+ public void deleteRepositoryData() {
+ ((IRepositoryAdministration) Repository.INSTANCE).doClear();
+ }
+
+ @GET
+ @Produces(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP)
+ public Response dumpRepository() {
+ StreamingOutput so = new StreamingOutput() {
+
+ @Override
+ public void write(OutputStream output) throws IOException, WebApplicationException {
+ ((IRepositoryAdministration) Repository.INSTANCE).doDump(output);
+ }
+ };
+ StringBuilder sb = new StringBuilder();
+ sb.append("attachment;filename=\"repository.zip\"");
+ return Response.ok().header("Content-Disposition", sb.toString()).type(org.eclipse.winery.common.constants.MimeTypes.MIMETYPE_ZIP).entity(so).build();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java
new file mode 100644
index 0000000..bf3c024
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/AbstractTypesManager.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin.types;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.datatypes.TypeWithShortName;
+import org.eclipse.winery.repository.datatypes.ids.admin.TypesId;
+import org.eclipse.winery.repository.datatypes.select2.Select2DataItem;
+import org.eclipse.winery.repository.resources.admin.AbstractAdminResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Handles longname/shortname by using properties
+ *
+ * FIXME: This class does NOT support dynamic reloading of the underlying
+ * Configuration instance
+ *
+ */
+public abstract class AbstractTypesManager extends AbstractAdminResource {
+
+ @Context
+ private UriInfo uriInfo;
+
+ protected static final Logger logger = LoggerFactory.getLogger(AbstractTypesManager.class);
+
+ // hashes from a long type string to the type object holding complete type data
+ private final HashMap<String, TypeWithShortName> hashTypeStringToType;
+
+
+ public AbstractTypesManager(TypesId id) {
+ super(id);
+ // now, this.configuration is filled with stored data
+
+ // copy over information from configuration to internal data structure
+ this.hashTypeStringToType = new HashMap<String, TypeWithShortName>();
+ Iterator<String> keys = this.configuration.getKeys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ String value = this.configuration.getString(key);
+ TypeWithShortName typeInfo = new TypeWithShortName(key, value);
+ this.hashTypeStringToType.put(key, typeInfo);
+ }
+ }
+
+ protected void addData(String longName, String shortName) {
+ TypeWithShortName t = new TypeWithShortName(longName, shortName);
+ this.addData(t);
+ }
+
+ /**
+ * Adds data to the internal data structure WITHOUT persisting it
+ *
+ * More or less a quick hack to enable adding default types without
+ * persisting them in the storage
+ *
+ * @param t the type to add
+ */
+ private void addData(TypeWithShortName t) {
+ this.hashTypeStringToType.put(t.getType(), t);
+ }
+
+ public synchronized void addTypeWithShortName(TypeWithShortName type) {
+ this.addData(type);
+ this.configuration.setProperty(type.getType(), type.getShortName());
+ }
+
+ /**
+ * Removes a type. Will not remove a type added by "addData"
+ */
+ @DELETE
+ @Path("{type}")
+ public Response removeTypeWithResponse(@PathParam("type") String type) {
+ type = Util.URLdecode(type);
+ if (this.configuration.containsKey(type)) {
+ this.hashTypeStringToType.remove(type);
+ this.configuration.clearProperty(type);
+ return Response.noContent().build();
+ } else if (this.hashTypeStringToType.containsKey(type)) {
+ // predefined types may not be deleted
+ // this branch is hit at types added via addData (e.g., predefined plantypes)
+ return Response.status(Status.FORBIDDEN).build();
+ } else {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ }
+
+ /**
+ * Returns a sorted list of all available types
+ */
+ public Collection<TypeWithShortName> getTypes() {
+ Collection<TypeWithShortName> res = new TreeSet<TypeWithShortName>(this.hashTypeStringToType.values());
+ return res;
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Object getTypesAsJSONArrayList(@QueryParam("select2") String select2) {
+ if (select2 == null) {
+ return this.getTypes();
+ } else {
+ // select2 mode
+ SortedSet<Select2DataItem> res = new TreeSet<>();
+ for (TypeWithShortName t : this.getTypes()) {
+ Select2DataItem item = new Select2DataItem(t.getType(), t.getShortName());
+ res.add(item);
+ }
+ return res;
+ }
+ }
+
+ /**
+ * <b>SIDEEFFECT:</b> If there currently isn't any short type name, it is
+ * created
+ */
+ public TypeWithShortName getTypeWithShortName(String typeString) {
+ TypeWithShortName t = this.hashTypeStringToType.get(typeString);
+ if (t == null) {
+ String shortName = this.getShortName(typeString);
+ t = new TypeWithShortName(typeString, shortName);
+ this.addTypeWithShortName(t);
+ }
+ return t;
+ }
+
+ /**
+ * <b>SIDEEFFECT:</b> If there currently isn't any short type name, it is
+ * created
+ */
+ public String getShortName(String typeString) {
+ TypeWithShortName type = this.hashTypeStringToType.get(typeString);
+ String res;
+ if (type == null) {
+ // happens if artifact type is not registered in artifacttypes.list
+ // (DATAFILENAME)
+ res = typeString;
+ } else {
+ res = type.getShortName();
+ }
+ return res;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML(@Context UriInfo uriInfo) {
+ this.uriInfo = uriInfo;
+ return new Viewable("/jsp/admin/types/types.jsp", this);
+ }
+
+ @POST
+ public Response updateTypeMapping(@FormParam("shortname") String shortName, @FormParam("type") String type) {
+ if (StringUtils.isEmpty(shortName)) {
+ return Response.status(Status.BAD_REQUEST).entity("shortName has to be given").build();
+ }
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).entity("type has to be given").build();
+ }
+ shortName = Util.URLdecode(shortName);
+ type = Util.URLdecode(type);
+ TypeWithShortName tws = new TypeWithShortName(type, shortName);
+ this.addTypeWithShortName(tws);
+ return Response.noContent().build();
+ }
+
+ /**
+ * Required by types.jsp
+ */
+ public String getURL() {
+ return this.uriInfo.getAbsolutePath().toString();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java
new file mode 100644
index 0000000..d8a9c0e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/ConstraintTypesManager.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin.types;
+
+import org.eclipse.winery.repository.datatypes.ids.admin.ConstraintTypesId;
+
+public class ConstraintTypesManager extends AbstractTypesManager {
+
+ public final static ConstraintTypesManager INSTANCE = new ConstraintTypesManager();
+
+
+ private ConstraintTypesManager() {
+ super(new ConstraintTypesId());
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java
new file mode 100644
index 0000000..e5b35b9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanLanguagesManager.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin.types;
+
+import org.eclipse.winery.repository.datatypes.ids.admin.PlanLanguagesId;
+
+public class PlanLanguagesManager extends AbstractTypesManager {
+
+ public final static PlanLanguagesManager INSTANCE = new PlanLanguagesManager();
+
+
+ private PlanLanguagesManager() {
+ super(new PlanLanguagesId());
+ // add data without rendering in the plan languages file
+ this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE, "BPEL 2.0 (executable)");
+ this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPMN20_MODEL, "BPMN 2.0");
+ this.addData(org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20, "BPMN4TOSCA 2.0");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java
new file mode 100644
index 0000000..de6e7ba
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/admin/types/PlanTypesManager.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.admin.types;
+
+import org.eclipse.winery.repository.datatypes.ids.admin.PlanTypesId;
+
+public class PlanTypesManager extends AbstractTypesManager {
+
+ public final static PlanTypesManager INSTANCE = new PlanTypesManager();
+
+
+ private PlanTypesManager() {
+ super(new PlanTypesId());
+ // add data without rendering in the plan types file
+ this.addData(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN, "Build Plan");
+ this.addData(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_TERMINATION_PLAN, "Termination Plan");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java
new file mode 100644
index 0000000..ec7a86b
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactResource.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.artifacts;
+
+import java.util.List;
+
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+
+public class DeploymentArtifactResource extends GenericArtifactResource<TDeploymentArtifact> {
+
+ private final TDeploymentArtifact a;
+
+
+ /**
+ * Converts the given artifactId to an DeploymentArtifact.
+ *
+ * <em>SIDE EFFECT</em> Adds it to the DeploymentArtifacts list if it does
+ * not yet exist.
+ */
+ private static TDeploymentArtifact getDeploymentArtifact(String artifactId, List<TDeploymentArtifact> deploymentArtifacts) {
+ for (TDeploymentArtifact ia : deploymentArtifacts) {
+ if (ia.getName().equals(artifactId)) {
+ return ia;
+ }
+ }
+ // DA does not exist in list
+ TDeploymentArtifact ia = new TDeploymentArtifact();
+ ia.setName(artifactId);
+ deploymentArtifacts.add(ia);
+ return ia;
+ }
+
+ public DeploymentArtifactResource(String artifactId, List<TDeploymentArtifact> deploymentArtifacts, IPersistable res) {
+ this(DeploymentArtifactResource.getDeploymentArtifact(artifactId, deploymentArtifacts), deploymentArtifacts, res);
+ }
+
+ public DeploymentArtifactResource(IIdDetermination<TDeploymentArtifact> idDetermination, TDeploymentArtifact o, int idx, List<TDeploymentArtifact> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ this.a = o;
+ }
+
+ public DeploymentArtifactResource(TDeploymentArtifact deploymentArtifact, List<TDeploymentArtifact> deploymentArtifacts, IPersistable res) {
+ this(new IIdDetermination<TDeploymentArtifact>() {
+
+ @Override
+ public String getId(TDeploymentArtifact e) {
+ return e.getName();
+ }
+ }, deploymentArtifact, deploymentArtifacts.indexOf(deploymentArtifact), deploymentArtifacts, res);
+ }
+
+ public TDeploymentArtifact getDeploymentArtifact() {
+ return this.a;
+ }
+
+ @Override
+ public void setArtifactType(ArtifactTypeId artifactTypeId) {
+ this.getDeploymentArtifact().setArtifactType(artifactTypeId.getQName());
+ BackendUtils.persist(this.res);
+ }
+
+ @Override
+ public void setArtifactTemplate(ArtifactTemplateId artifactTemplateId) {
+ this.getDeploymentArtifact().setArtifactRef(artifactTemplateId.getQName());
+ BackendUtils.persist(this.res);
+ }
+
+ @Override
+ public TDeploymentArtifact getA() {
+ return this.a;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java
new file mode 100644
index 0000000..dcb5ca7
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/DeploymentArtifactsResource.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.artifacts;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.model.tosca.TDeploymentArtifacts;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DeploymentArtifactsResource extends GenericArtifactsResource<DeploymentArtifactResource, TDeploymentArtifact> {
+
+ private static final Logger logger = LoggerFactory.getLogger(DeploymentArtifactsResource.class);
+
+ private List<TDeploymentArtifact> deploymentArtifacts;
+
+
+ public DeploymentArtifactsResource(List<TDeploymentArtifact> deploymentArtifact, INodeTemplateResourceOrNodeTypeImplementationResource res) {
+ super(DeploymentArtifactResource.class, TDeploymentArtifact.class, deploymentArtifact, res);
+ this.deploymentArtifacts = deploymentArtifact;
+ }
+
+ /**
+ * Determines the list of DAs belonging to the given node template.
+ *
+ * If no DAs are existing, an empty list is created in the model for the
+ * node template
+ */
+ private static List<TDeploymentArtifact> getDeploymentArtifacts(TNodeTemplate nodeTemplate) {
+ TDeploymentArtifacts deploymentArtifacts = nodeTemplate.getDeploymentArtifacts();
+ final List<TDeploymentArtifact> res;
+ if (deploymentArtifacts == null) {
+ deploymentArtifacts = new TDeploymentArtifacts();
+ nodeTemplate.setDeploymentArtifacts(deploymentArtifacts);
+ }
+ res = deploymentArtifacts.getDeploymentArtifact();
+ return res;
+ }
+
+ public DeploymentArtifactsResource(TNodeTemplate nodeTemplate, INodeTemplateResourceOrNodeTypeImplementationResource res) {
+ this(DeploymentArtifactsResource.getDeploymentArtifacts(nodeTemplate), res);
+ }
+
+ @Override
+ public Collection<DeploymentArtifactResource> getAllArtifactResources() {
+ Collection<DeploymentArtifactResource> res = new ArrayList<DeploymentArtifactResource>(this.deploymentArtifacts.size());
+ for (TDeploymentArtifact da : this.deploymentArtifacts) {
+ DeploymentArtifactResource r = new DeploymentArtifactResource(da, this.deploymentArtifacts, this.res);
+ res.add(r);
+ }
+ return res;
+ }
+
+ @Override
+ public String getId(TDeploymentArtifact entity) {
+ return entity.getName();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java
new file mode 100644
index 0000000..9295082
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactResource.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.artifacts;
+
+import java.util.List;
+
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+
+/**
+ * Currently no common things for deployment artifacts and implementation
+ * artifacts as the data model also has no common ancestor (besides
+ * TExensibleElement)
+ */
+public abstract class GenericArtifactResource<ArtifactT> extends EntityWithIdResource<ArtifactT> {
+
+ public GenericArtifactResource(IIdDetermination<ArtifactT> idDetermination, ArtifactT o, int idx, List<ArtifactT> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ public abstract void setArtifactType(ArtifactTypeId artifactTypeId);
+
+ public abstract void setArtifactTemplate(ArtifactTemplateId artifactTemplateId);
+
+ /**
+ * required by artifacts.jsp
+ */
+ public abstract ArtifactT getA();
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java
new file mode 100644
index 0000000..0cef56e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/GenericArtifactsResource.java
@@ -0,0 +1,572 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.artifacts;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.generators.ia.Generator;
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.model.tosca.TEntityTemplate.Properties;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact;
+import org.eclipse.winery.model.tosca.TInterface;
+import org.eclipse.winery.model.tosca.TNodeType;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.backend.ResourceCreationResult;
+import org.eclipse.winery.repository.backend.filebased.FileUtils;
+import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.IHasTypeReference;
+import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource;
+import org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates.ArtifactTemplateResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+import org.xml.sax.InputSource;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Resource handling both deployment and implementation artifacts
+ *
+ */
+public abstract class GenericArtifactsResource<ArtifactResource extends GenericArtifactResource<ArtifactT>, ArtifactT> extends EntityWithIdCollectionResource<ArtifactResource, ArtifactT> {
+
+ private static final Logger logger = LoggerFactory.getLogger(GenericArtifactsResource.class);
+
+ protected final INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource resWithNamespace;
+
+
+ public GenericArtifactsResource(Class<ArtifactResource> entityResourceTClazz, Class<ArtifactT> entityTClazz, List<ArtifactT> list, INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
+ super(entityResourceTClazz, entityTClazz, list, GenericArtifactsResource.getAbstractComponentInstanceResource(res));
+ this.resWithNamespace = res;
+ }
+
+ // @formatter:off
+
+ /**
+ * @return TImplementationArtifact | TDeploymentArtifact (XML) | URL of generated IA zip (in case of autoGenerateIA)
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_XML)
+ @RestDoc(methodDescription = "Creates a new implementation/deployment artifact. " +
+ "If an implementation artifact with the same name already exists, it is <em>overridden</em>.")
+ @SuppressWarnings("unchecked")
+ public Response onPost(
+ @FormParam("artifactName")
+ @RestDocParam(description = "This is the name of the implementation/deployment artifact. " +
+ "Is <em>also</em>used as prefix of the name of the corresponding artifact template if no specific template is provided. " +
+ "In contrast to CS01, we require a artifactName also for the implementationArtifact to be able to properly referencing it.")
+ String artifactNameStr,
+
+ @FormParam("artifactTemplate")
+ @RestDocParam(description = "QName of the artifact Template - used by Winery Backend instead of artifactTemplateName + artifactTemplateNS")
+ String artifactTemplate,
+
+ @FormParam("artifactTemplateName")
+ @RestDocParam(description = "if provided and autoCreateArtifactTemplate, a template of this id localname and artifactTemplateNS generated. " +
+ "Winery always sends this string if auto creation is desired.")
+ String artifactTemplateName,
+
+ @FormParam("artifactTemplateNS")
+ String artifactTemplateNS,
+
+ @FormParam("autoCreateArtifactTemplate")
+ @RestDocParam(description = "if empty, no, or false, no artifact template is created. " +
+ "An artifact type has to be given in that case. " +
+ "Furthermore, an artifact template name + artifact template namespace has to be provided. " +
+ "Otherwise, the artifactNameStr is used as name for the artifact and a <em>new</em> artifact template is created having {@code <artifactNameString>Template} as name")
+ String autoCreateArtifactTemplate,
+
+ @FormParam("artifactType")
+ @RestDocParam(description = "QName of the type, format: {namespace}localname. " +
+ "Optional if artifactTemplateName + artifactTempalteNS is provided")
+ String artifactTypeStr,
+
+ @FormParam("artifactSpecificContent")
+ @RestDocParam(description = "<em>XML</em> snippet that should be put inside the artifact XML in the TOSCA serialization. " +
+ "This feature will be removed soon. " +
+ "TODO: This only works if there is a single child element expected and not several elements. " +
+ "Future versions of the Winery will support arbitrary content there.")
+ String artifactSpecificContent,
+
+ @FormParam("interfaceName")
+ String interfaceNameStr,
+
+ @FormParam("operationName")
+ String operationNameStr,
+
+ @FormParam("autoGenerateIA")
+ @RestDocParam(description = "If not empty, the IA generator will be called")
+ String autoGenerateIA,
+
+ @FormParam("javapackage")
+ @RestDocParam(description = "The Java package to use for IA generation")
+ String javapackage,
+
+ @Context UriInfo uriInfo
+ ){
+ // we assume that the parent ComponentInstance container exists
+
+ // @formatter:on
+
+ if (StringUtils.isEmpty(artifactNameStr)) {
+ return Response.status(Status.BAD_REQUEST).entity("Empty artifactName").build();
+ }
+ if (StringUtils.isEmpty(artifactTypeStr)) {
+ if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) {
+ if (StringUtils.isEmpty(artifactTemplate)) {
+ return Response.status(Status.BAD_REQUEST).entity("No artifact type given and no template given. Cannot guess artifact type").build();
+ }
+ }
+ }
+
+ if (!StringUtils.isEmpty(autoGenerateIA)) {
+ if (StringUtils.isEmpty(javapackage)) {
+ return Response.status(Status.BAD_REQUEST).entity("no java package name supplied for IA auto generation.").build();
+ }
+ if (StringUtils.isEmpty(interfaceNameStr)) {
+ return Response.status(Status.BAD_REQUEST).entity("no interface name supplied for IA auto generation.").build();
+ }
+ }
+
+ // convert second calling form to first calling form
+ if (!StringUtils.isEmpty(artifactTemplate)) {
+ QName qname = QName.valueOf(artifactTemplate);
+ artifactTemplateName = qname.getLocalPart();
+ artifactTemplateNS = qname.getNamespaceURI();
+ }
+
+ Document doc = null;
+
+ // check artifact specific content for validity
+ // if invalid, abort and do not create anything
+ if (!StringUtils.isEmpty(artifactSpecificContent)) {
+ try {
+ DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ InputSource is = new InputSource();
+ StringReader sr = new StringReader(artifactSpecificContent);
+ is.setCharacterStream(sr);
+ doc = db.parse(is);
+ } catch (Exception e) {
+ // FIXME: currently we allow a single element only. However, the content should be internally wrapped by an (arbitrary) XML element as the content will be nested in the artifact element, too
+ GenericArtifactsResource.logger.debug("Invalid content", e);
+ return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
+ }
+ }
+
+ // determine artifactTemplate and artifactType
+
+ ArtifactTypeId artifactTypeId;
+ ArtifactTemplateId artifactTemplateId = null;
+ ArtifactTemplateResource artifactTemplateResource = null;
+
+ boolean doAutoCreateArtifactTemplate = !(StringUtils.isEmpty(autoCreateArtifactTemplate) || autoCreateArtifactTemplate.equalsIgnoreCase("no") || autoCreateArtifactTemplate.equalsIgnoreCase("false"));
+ if (!doAutoCreateArtifactTemplate) {
+ // no auto creation
+ if (!StringUtils.isEmpty(artifactTemplateName) && !StringUtils.isEmpty(artifactTemplateNS)) {
+ QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName);
+ artifactTemplateId = BackendUtils.getTOSCAcomponentId(ArtifactTemplateId.class, artifactTemplateQName);
+ }
+ if (StringUtils.isEmpty(artifactTypeStr)) {
+ // derive the type from the artifact template
+ if (artifactTemplateId == null) {
+ return Response.status(Status.NOT_ACCEPTABLE).entity("No artifactTemplate and no artifactType provided. Deriving the artifactType is not possible.").build();
+ }
+ artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId);
+ artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTemplateResource.getType());
+ } else {
+ // artifactTypeStr is directly given, use that
+ artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr);
+ }
+ } else {
+ // do the artifact template auto creation magic
+
+ if (StringUtils.isEmpty(artifactTypeStr)) {
+ return Response.status(Status.BAD_REQUEST).entity("Artifact template auto creation requested, but no artifact type supplied.").build();
+ }
+
+ // we assume that the type points to a valid artifact type
+ artifactTypeId = BackendUtils.getTOSCAcomponentId(ArtifactTypeId.class, artifactTypeStr);
+
+ if (StringUtils.isEmpty(artifactTemplateName) || StringUtils.isEmpty(artifactTemplateNS)) {
+ // no explicit name provided
+ // we use the artifactNameStr as prefix for the
+ // artifact template name
+
+ // we create a new artifact template in the namespace of the parent
+ // element
+ Namespace namespace = this.resWithNamespace.getNamespace();
+
+ artifactTemplateId = new ArtifactTemplateId(namespace, new XMLId(artifactNameStr + "artifactTemplate", false));
+ } else {
+ QName artifactTemplateQName = new QName(artifactTemplateNS, artifactTemplateName);
+ artifactTemplateId = new ArtifactTemplateId(artifactTemplateQName);
+ }
+ ResourceCreationResult creationResult = BackendUtils.create(artifactTemplateId);
+ if (!creationResult.isSuccess()) {
+ // something went wrong. skip
+ return creationResult.getResponse();
+ }
+
+ // associate the type to the created artifact template
+ artifactTemplateResource = new ArtifactTemplateResource(artifactTemplateId);
+ // set the type. The resource is automatically persisted inside
+ artifactTemplateResource.setType(artifactTypeStr);
+ }
+
+ // variable artifactTypeId is set
+ // variable artifactTemplateId is not null if artifactTemplate has been generated
+
+ // we have to generate the DA/IA resource now
+ // Doing it here instead of doing it at the subclasses is dirty on the
+ // one hand, but quicker to implement on the other hand
+
+ // Create the artifact itself
+
+ ArtifactT resultingArtifact;
+
+ if (this instanceof ImplementationArtifactsResource) {
+ ImplementationArtifact a = new ImplementationArtifact();
+ // Winery internal id is the name of the artifact:
+ // store the name
+ a.setName(artifactNameStr);
+ a.setInterfaceName(interfaceNameStr);
+ a.setOperationName(operationNameStr);
+ assert (artifactTypeId != null);
+ a.setArtifactType(artifactTypeId.getQName());
+ if (artifactTemplateId != null) {
+ a.setArtifactRef(artifactTemplateId.getQName());
+ }
+ if (doc != null) {
+ // the content has been checked for validity at the beginning of the method.
+ // If this point in the code is reached, the XML has been parsed into doc
+ // just copy over the dom node. Hopefully, that works...
+ a.getAny().add(doc.getDocumentElement());
+ }
+
+ this.list.add((ArtifactT) a);
+ resultingArtifact = (ArtifactT) a;
+ } else {
+ // for comments see other branch
+
+ TDeploymentArtifact a = new TDeploymentArtifact();
+ a.setName(artifactNameStr);
+ assert (artifactTypeId != null);
+ a.setArtifactType(artifactTypeId.getQName());
+ if (artifactTemplateId != null) {
+ a.setArtifactRef(artifactTemplateId.getQName());
+ }
+ if (doc != null) {
+ a.getAny().add(doc.getDocumentElement());
+ }
+
+ this.list.add((ArtifactT) a);
+ resultingArtifact = (ArtifactT) a;
+ }
+
+ Response persistResponse = BackendUtils.persist(super.res);
+ // TODO: check for error and in case one found return that
+
+ if (StringUtils.isEmpty(autoGenerateIA)) {
+ // no IA generation
+ // we include an XML for the data table
+
+ String implOrDeplArtifactXML = Utils.getXMLAsString(resultingArtifact);
+
+ return Response.created(Utils.createURI(Util.URLencode(artifactNameStr))).entity(implOrDeplArtifactXML).build();
+ } else {
+ // after everything was created, we fire up the artifact generation
+ return this.generateImplementationArtifact(interfaceNameStr, javapackage, uriInfo, artifactTemplateId, artifactTemplateResource);
+ }
+ }
+
+ /**
+ * Generates a unique and valid name to be used for the generated maven
+ * project name, java project name, class name, port type name.
+ */
+ private String generateName(NodeTypeId nodeTypeId, String interfaceName) {
+ String name = Util.namespaceToJavaPackage(nodeTypeId.getNamespace().getDecoded());
+ name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
+
+ // Winery already ensures that this is a valid NCName
+ // getName() returns the id of the nodeType: A nodeType carries the "id" attribute only (and no name attribute)
+ name += nodeTypeId.getXmlId().getDecoded();
+
+ // Two separators to distinguish node type and interface part
+ name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
+ name += Util.FORBIDDEN_CHARACTER_REPLACEMENT;
+ name += Util.namespaceToJavaPackage(interfaceName);
+
+ // In addition we must replace '.', because Java class names must not
+ // contain dots, but for Winery they are fine.
+ return name.replace(".", Util.FORBIDDEN_CHARACTER_REPLACEMENT);
+ }
+
+ /**
+ * Generates the implementation artifact using the implementation artifact
+ * generator. Also sets the proeprties according to the requirements of
+ * OpenTOSCA.
+ *
+ * @param interfaceNameStr
+ * @param javapackage
+ * @param uriInfo
+ * @param artifactTemplateId
+ * @param artifactTemplateResource the resource associated with the
+ * artifactTempalteId. If null, the object is created in this
+ * method
+ *
+ * @return {@inheritDoc}
+ */
+ private Response generateImplementationArtifact(String interfaceNameStr, String javapackage, UriInfo uriInfo, ArtifactTemplateId artifactTemplateId, ArtifactTemplateResource artifactTemplateResource) {
+ TInterface iface;
+
+ assert (this instanceof ImplementationArtifactsResource);
+ IHasTypeReference typeRes = (EntityTypeImplementationResource) this.res;
+ QName type = typeRes.getType();
+ TOSCAComponentId typeId;
+ TNodeType nodeType = null;
+ if (typeRes instanceof NodeTypeImplementationResource) {
+ // TODO: refactor: This is more a model/repo utilities thing than something which should happen here...
+
+ typeId = new NodeTypeId(type);
+ NodeTypeResource ntRes = (NodeTypeResource) AbstractComponentsResource.getComponentInstaceResource(typeId);
+
+ // required for IA Generation
+ nodeType = ntRes.getNodeType();
+
+ List<TInterface> interfaces = nodeType.getInterfaces().getInterface();
+ Iterator<TInterface> it = interfaces.iterator();
+ do {
+ iface = it.next();
+ if (iface.getName().equals(interfaceNameStr)) {
+ break;
+ }
+ } while (it.hasNext());
+ // iface now contains the right interface
+ } else {
+ assert (typeRes instanceof RelationshipTypeImplementationResource);
+ return Response.serverError().entity("IA creation for relation ship type implementations not yet possible").build();
+ }
+
+ Path workingDir;
+ try {
+ workingDir = Files.createTempDirectory("winery");
+ } catch (IOException e2) {
+ GenericArtifactsResource.logger.debug("Could not create temporary directory", e2);
+ return Response.serverError().entity("Could not create temporary directory").build();
+ }
+
+ URI artifactTemplateFilesUri = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(artifactTemplateId)).resolve("files/");
+ URL artifactTemplateFilesUrl;
+ try {
+ artifactTemplateFilesUrl = artifactTemplateFilesUri.toURL();
+ } catch (MalformedURLException e2) {
+ GenericArtifactsResource.logger.debug("Could not convert URI to URL", e2);
+ return Response.serverError().entity("Could not convert URI to URL").build();
+ }
+
+ String name = this.generateName((NodeTypeId) typeId, interfaceNameStr);
+ Generator gen = new Generator(iface, javapackage, artifactTemplateFilesUrl, name, workingDir.toFile());
+ File zipFile = gen.generateProject();
+ if (zipFile == null) {
+ return Response.serverError().entity("IA generator failed").build();
+ }
+
+ // store it
+ // TODO: refactor: this is more a RepositoryUtils thing than a special thing here; see also importFile at CSARImporter
+
+ ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId(artifactTemplateId);
+ RepositoryFileReference fref = new RepositoryFileReference(fileDir, zipFile.getName().toString());
+ try (InputStream is = Files.newInputStream(zipFile.toPath());
+ BufferedInputStream bis = new BufferedInputStream(is)) {
+ String mediaType = Utils.getMimeType(bis, zipFile.getName());
+ // TODO: do the catch thing as in CSARImporter
+
+ Repository.INSTANCE.putContentToFile(fref, bis, MediaType.valueOf(mediaType));
+ } catch (IOException e1) {
+ throw new IllegalStateException("Could not import generated files", e1);
+ }
+
+ // cleanup dir
+ try {
+ FileUtils.forceDelete(workingDir);
+ } catch (IOException e) {
+ GenericArtifactsResource.logger.debug("Could not delete working directory", e);
+ }
+
+ // store the properties in the artifact template
+ if (artifactTemplateResource == null) {
+ artifactTemplateResource = (ArtifactTemplateResource) AbstractComponentsResource.getComponentInstaceResource(artifactTemplateId);
+ }
+ this.storeProperties(artifactTemplateResource, typeId, name);
+
+ URI url = uriInfo.getBaseUri().resolve(Utils.getAbsoluteURL(fref));
+ return Response.created(url).build();
+ }
+
+
+ private final String NS_OPENTOSCA_WAR_TYPE = "http://www.uni-stuttgart.de/opentosca";
+
+
+ private void storeProperties(ArtifactTemplateResource artifactTemplateResource, TOSCAComponentId typeId, String name) {
+ // We generate the properties by hand instead of using JAX-B as using JAX-B causes issues at org.eclipse.winery.common.ModelUtilities.getPropertiesKV(TEntityTemplate):
+ // getAny() does not always return "w3c.dom.element" anymore
+
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder;
+ try {
+ builder = dbf.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ GenericArtifactsResource.logger.error(e.getMessage(), e);
+ return;
+ }
+ Document doc = builder.newDocument();
+ Element root = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "WSProperties");
+ doc.appendChild(root);
+
+ Element element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "ServiceEndpoint");
+ Text text = doc.createTextNode("/services/" + name + "Port");
+ element.appendChild(text);
+ root.appendChild(element);
+
+ element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "PortType");
+ text = doc.createTextNode("{" + typeId.getNamespace().getDecoded() + "}" + name);
+ element.appendChild(text);
+ root.appendChild(element);
+
+ element = doc.createElementNS(this.NS_OPENTOSCA_WAR_TYPE, "InvocationType");
+ text = doc.createTextNode("SOAP/HTTP");
+ element.appendChild(text);
+ root.appendChild(element);
+
+ Properties properties = new Properties();
+ properties.setAny(root);
+ PropertiesResource propertiesResource = artifactTemplateResource.getPropertiesResource();
+ propertiesResource.setProperties(properties);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/artifacts/artifacts.jsp", this);
+ }
+
+ /**
+ * Required for artifacts.jsp
+ *
+ * @return list of known artifact types.
+ */
+ public List<QName> getAllArtifactTypes() {
+ SortedSet<ArtifactTypeId> allArtifactTypes = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class);
+ List<QName> res = new ArrayList<QName>(allArtifactTypes.size());
+ for (ArtifactTypeId id : allArtifactTypes) {
+ res.add(id.getQName());
+ }
+ return res;
+ }
+
+ /**
+ * Required for artifacts.jsp
+ *
+ * @return list of all contained artifacts.
+ */
+ public abstract Collection<ArtifactResource> getAllArtifactResources();
+
+ /**
+ * Required by artifact.jsp to decide whether to display
+ * "Deployment Artifact" or "Implementation Artifact"
+ */
+ public boolean getIsDeploymentArtifacts() {
+ boolean res = (this instanceof DeploymentArtifactsResource);
+ return res;
+ }
+
+ /**
+ * required by artifacts.jsp
+ */
+ public String getNamespace() {
+ return this.resWithNamespace.getNamespace().getDecoded();
+ }
+
+ /**
+ * For saving resources, an AbstractComponentInstanceResource is required.
+ * DAs may be attached to a node template, which is not an
+ * AbstractComponentInstanceResource, but its grandparent resource
+ * ServiceTemplate is
+ *
+ * @param res the resource to determine the the
+ * AbstractComponentInstanceResource for
+ * @return the AbstractComponentInstanceResource where the given res is
+ * contained in
+ */
+ public static AbstractComponentInstanceResource getAbstractComponentInstanceResource(INodeTemplateResourceOrNodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
+ final AbstractComponentInstanceResource r;
+ if (res instanceof NodeTemplateResource) {
+ r = ((NodeTemplateResource) res).getServiceTemplateResource();
+ } else {
+ // quick hack: the resource has to be an abstract component instance
+ r = (AbstractComponentInstanceResource) res;
+ }
+ return r;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java
new file mode 100644
index 0000000..bc5580c
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactResource.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.artifacts;
+
+import java.util.List;
+
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+
+public class ImplementationArtifactResource extends GenericArtifactResource<ImplementationArtifact> {
+
+ private ImplementationArtifact a;
+
+
+ /**
+ * Converts the given artifactId to an ImplementArtifact.
+ *
+ * <em>SIDE EFFECT</em> Adds it to the implementationArtifacts list if it
+ * does not yet exist.
+ */
+ private static ImplementationArtifact getImplementationArtifact(String artifactId, List<ImplementationArtifact> implementationArtifacts) {
+ if (artifactId == null) {
+ throw new IllegalArgumentException("artifactId must not be null");
+ }
+ if (implementationArtifacts == null) {
+ throw new IllegalArgumentException("implementationArtifacts must not be null");
+ }
+ for (ImplementationArtifact ia : implementationArtifacts) {
+ // ia.getName() might be null as TOSCA COS01 does not forsee a name on the implementation artifact
+ // Therefore, we begin the test with "artifactId"
+ if (artifactId.equals(ia.getName())) {
+ return ia;
+ }
+ }
+ // IA does not exist in list
+ ImplementationArtifact ia = new ImplementationArtifact();
+ ia.setName(artifactId);
+ implementationArtifacts.add(ia);
+ return ia;
+ }
+
+ public ImplementationArtifactResource(String artifactId, List<ImplementationArtifact> implementationArtifacts, IPersistable res) {
+ this(ImplementationArtifactResource.getImplementationArtifact(artifactId, implementationArtifacts), implementationArtifacts, res);
+ }
+
+ public ImplementationArtifactResource(IIdDetermination<ImplementationArtifact> idDetermination, ImplementationArtifact o, int idx, List<ImplementationArtifact> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ this.a = o;
+ }
+
+ public ImplementationArtifactResource(ImplementationArtifact a, List<ImplementationArtifact> implementationArtifacts, IPersistable res) {
+ this(new IIdDetermination<ImplementationArtifact>() {
+
+ @Override
+ public String getId(ImplementationArtifact e) {
+ return e.getName();
+ }
+ }, a, implementationArtifacts.indexOf(a), implementationArtifacts, res);
+ }
+
+ public ImplementationArtifact getImplementationArtifact() {
+ return this.a;
+ }
+
+ @Override
+ public void setArtifactType(ArtifactTypeId artifactTypeId) {
+ this.getImplementationArtifact().setArtifactType(artifactTypeId.getQName());
+ BackendUtils.persist(this.res);
+ }
+
+ @Override
+ public void setArtifactTemplate(ArtifactTemplateId artifactTemplateId) {
+ this.getImplementationArtifact().setArtifactRef(artifactTemplateId.getQName());
+ BackendUtils.persist(this.res);
+ }
+
+ @Override
+ public ImplementationArtifact getA() {
+ return this.a;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java
new file mode 100644
index 0000000..e1d7aa6
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/artifacts/ImplementationArtifactsResource.java
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.artifacts;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.model.tosca.TImplementationArtifacts.ImplementationArtifact;
+import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypesResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypesResource;
+import org.eclipse.winery.repository.resources.interfaces.InterfaceResource;
+
+/**
+ * ImplementationArtifact instead of TImplementationArtifact has to be used
+ * because of difference in the XSD at tImplementationArtifacts vs.
+ * tDeploymentArtifacts
+ */
+public class ImplementationArtifactsResource extends GenericArtifactsResource<ImplementationArtifactResource, ImplementationArtifact> {
+
+ private List<ImplementationArtifact> implementationArtifacts;
+
+
+ public ImplementationArtifactsResource(List<ImplementationArtifact> implementationArtifact, INodeTypeImplementationResourceOrRelationshipTypeImplementationResource res) {
+ super(ImplementationArtifactResource.class, ImplementationArtifact.class, implementationArtifact, res);
+ this.implementationArtifacts = implementationArtifact;
+ }
+
+ /**
+ * @return a cast to TNodeTypeImplementationResource of the parent of this
+ * resource.
+ */
+ protected NodeTypeImplementationResource getNTI() {
+ return (NodeTypeImplementationResource) this.res;
+ }
+
+ /**
+ * @return a cast to TNodeTypeImplementationResource of the parent of this
+ * resource.
+ */
+ protected RelationshipTypeImplementationResource getRTI() {
+ return (RelationshipTypeImplementationResource) this.res;
+ }
+
+ @Override
+ public Collection<ImplementationArtifactResource> getAllArtifactResources() {
+ Collection<ImplementationArtifactResource> res = new ArrayList<ImplementationArtifactResource>(this.implementationArtifacts.size());
+ for (ImplementationArtifact da : this.implementationArtifacts) {
+ ImplementationArtifactResource r = new ImplementationArtifactResource(da, this.implementationArtifacts, this.res);
+ res.add(r);
+ }
+ return res;
+ }
+
+ /** required by artifacts.jsp **/
+ public List<InterfaceResource> getInterfacesOfAssociatedType() {
+ boolean isNodeTypeImplementation = this.res instanceof NodeTypeImplementationResource;
+ QName type;
+ List<InterfaceResource> interfaces = new ArrayList<InterfaceResource>();
+ if (isNodeTypeImplementation) {
+ type = this.getNTI().getType();
+ NodeTypeResource typeResource = (NodeTypeResource) new NodeTypesResource().getComponentInstaceResource(type);
+ interfaces.addAll(typeResource.getInterfaces().getAllEntityResources());
+ } else {
+ type = this.getRTI().getType();
+ RelationshipTypeResource typeResource = (RelationshipTypeResource) new RelationshipTypesResource().getComponentInstaceResource(type);
+ interfaces.addAll(typeResource.getSourceInterfaces().getAllEntityResources());
+ interfaces.addAll(typeResource.getTargetInterfaces().getAllEntityResources());
+ }
+ return interfaces;
+ }
+
+ @Override
+ public String getId(ImplementationArtifact entity) {
+ return entity.getName();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java
new file mode 100644
index 0000000..6783948
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationResource.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.documentation;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TDocumentation;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource;
+
+public class DocumentationResource extends EntityWithoutIdResource<TDocumentation> {
+
+ public DocumentationResource(TDocumentation o, int idx, List<TDocumentation> list, IPersistable res) {
+ super(o, idx, list, res);
+ }
+
+ @PUT
+ @Consumes(MediaType.TEXT_HTML)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response setValue(String documentation) {
+ this.o.getContent().clear();
+ this.o.getContent().add(documentation);
+ this.list.set(this.idx, this.o);
+ return CollectionsHelper.persist(this.res, this.idDetermination, this.o);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java
new file mode 100644
index 0000000..1466a57
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/documentation/DocumentationsResource.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.documentation;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.model.tosca.TDocumentation;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class DocumentationsResource extends EntityWithoutIdCollectionResource<DocumentationResource, TDocumentation> {
+
+ private static final Logger logger = LoggerFactory.getLogger(DocumentationResource.class);
+
+
+ public DocumentationsResource(IPersistable res, List<TDocumentation> documentations) {
+ super(DocumentationResource.class, TDocumentation.class, documentations, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/documentation.jsp", this.list);
+ }
+
+ /**
+ * Adds a new documentation
+ */
+ @POST
+ @Consumes(MediaType.TEXT_HTML)
+ public Response addNewElement(String documentation) {
+ if (documentation == null) {
+ return Response.status(Status.BAD_REQUEST).entity("No content provided").build();
+ }
+ TDocumentation doc = new TDocumentation();
+ doc.getContent().add(documentation);
+ // TODO: check for duplicates as in instance states
+ this.list.add(doc);
+ return CollectionsHelper.persist(this.res, this, doc);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java
new file mode 100644
index 0000000..e5025b1
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/IEntityTemplateResource.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.IHasTypeReference;
+
+/**
+ * Interface ensuring that no methods are forgotten when implementing an
+ * {@link AbstractComponentInstanceResource}, which is also a template
+ */
+public interface IEntityTemplateResource<E extends TEntityTemplate> extends IHasTypeReference {
+
+ @Path("properties/")
+ public PropertiesResource getPropertiesResource();
+
+ @DELETE
+ public Response onDelete();
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java
new file mode 100644
index 0000000..4341095
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/PropertiesResource.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class PropertiesResource {
+
+ private AbstractComponentInstanceResource res;
+ private TEntityTemplate template;
+
+
+ /**
+ * @param template the template to store the definitions at
+ * @param res the resource to save after modifications
+ */
+ public PropertiesResource(TEntityTemplate template, AbstractComponentInstanceResource res) {
+ this.template = template;
+ this.res = res;
+ }
+
+ /**
+ * Currently, properties can only be updated as a whole XML fragment
+ *
+ * Getting/setting a fragment of properties is not possible yet
+ */
+ @PUT
+ @Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML, MediaType.APPLICATION_JSON})
+ public Response setProperties(TEntityTemplate.Properties properties) {
+ this.getTemplate().setProperties(properties);
+ return BackendUtils.persist(this.res);
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytemplates/properties.jsp", this);
+ }
+
+ /** data for the JSP **/
+
+ public TEntityTemplate getTemplate() {
+ return this.template;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java
new file mode 100644
index 0000000..ee9064b
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplateResource.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates;
+
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.IHasTypeReference;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+
+public class TEntityTemplateResource<E extends TEntityTemplate> extends EntityWithIdResource<E> implements IEntityTemplateResource<E>, IHasTypeReference {
+
+ /**
+ * This constructor is used for both entity templates nested in an component
+ * instance as well as for entity templates being component instances
+ * itself.
+ *
+ * As Java does not support multi-inheritance, we implemented a quick hack
+ * to re-use this class as inner implementation at templates extending
+ * AbstractComponentInstanceResourceDefinitionsBacked
+ */
+ public TEntityTemplateResource(IIdDetermination<E> idDetermination, E o, int idx, List<E> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ // public String getId() {
+ // return this.template.getId();
+ // }
+ //
+ // public void setId(String id) {
+ // // TODO: There is no check for uniqueness of the given id
+ // this.template.setId(id);
+ // }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public QName getType() {
+ return this.o.getType();
+ }
+
+ @Path("type")
+ @GET
+ public String getTypeAsQNameString() {
+ return this.getType().toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Response setType(QName type) {
+ this.o.setType(type);
+ return BackendUtils.persist(this.res);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Response setType(String typeStr) {
+ return this.setType(QName.valueOf(typeStr));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PropertiesResource getPropertiesResource() {
+ return new PropertiesResource(this.o, (AbstractComponentInstanceResource) this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java
new file mode 100644
index 0000000..256e376
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/TEntityTemplatesResource.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+
+/**
+ * This resource models the list of TEntityTemplates
+ */
+public abstract class TEntityTemplatesResource<R extends EntityWithIdResource<T>, T extends TEntityTemplate> extends EntityWithIdCollectionResource<R, T> {
+
+ public TEntityTemplatesResource(Class<R> entityResourceTClazz, Class<T> entityTClazz, List<T> list, IPersistable res) {
+ super(entityResourceTClazz, entityTClazz, list, res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java
new file mode 100644
index 0000000..f3ed0e9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplateResource.java
@@ -0,0 +1,308 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.model.tosca.TArtifactReference;
+import org.eclipse.winery.model.tosca.TArtifactTemplate;
+import org.eclipse.winery.model.tosca.TArtifactTemplate.ArtifactReferences;
+import org.eclipse.winery.model.tosca.TDeploymentArtifact;
+import org.eclipse.winery.model.tosca.TDeploymentArtifacts;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImplementationArtifact;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TTopologyTemplate;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceWithReferencesResource;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.IHasName;
+import org.eclipse.winery.repository.resources.entitytemplates.IEntityTemplateResource;
+import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource;
+import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations.NodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations.RelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.entitytypes.artifacttypes.ArtifactTypeResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+
+/**
+ * Models an Artifact Template with its artifact references
+ *
+ * The associated files (through tArtifactReference) are stored directly within
+ * this resource. The element <ArtifactReference> is generated during export
+ * only
+ *
+ * This class inherits from AbstractComponentInstanceResourceDefinitionsBacked
+ * and not from TEntityTemplateResource<TArtifactTemplate>, because
+ * ArtifactTemplates are directly available under TDefinitions and we need the
+ * generic resource handling
+ */
+
+public class ArtifactTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IEntityTemplateResource<TArtifactTemplate>, IHasName {
+
+ private final TEntityTemplateResource<TArtifactTemplate> entityTemplateResource;
+
+
+ public ArtifactTemplateResource(ArtifactTemplateId id) {
+ super(id);
+ // we provide the minimum requirements for the resource
+ this.entityTemplateResource = new TEntityTemplateResource<TArtifactTemplate>(null, this.getTArtifactTemplate(), 0, null, this);
+ }
+
+ /**
+ * @return null if no artifact type resource is defined
+ */
+ public ArtifactTypeResource getAritfactTypeResource() {
+ ArtifactTypeId atId = new ArtifactTypeId(this.getTArtifactTemplate().getType());
+ return new ArtifactTypeResource(atId);
+ }
+
+ private TArtifactTemplate getTArtifactTemplate() {
+ return (TArtifactTemplate) this.element;
+ }
+
+ @Override
+ public String getName() {
+ String name = this.getTArtifactTemplate().getName();
+ if (name == null) {
+ return this.getTArtifactTemplate().getId();
+ } else {
+ return name;
+ }
+ }
+
+ @Override
+ public Response setName(String name) {
+ this.getTArtifactTemplate().setName(name);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TArtifactTemplate();
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ this.getTArtifactTemplate().setId(this.getId().getXmlId().getDecoded());
+ // Namespace cannot be set as the namespace is contained in TDefinitions only
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void synchronizeReferences() {
+ TArtifactTemplate template = this.getTArtifactTemplate();
+
+ ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId((ArtifactTemplateId) this.id);
+ SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(fileDir);
+ if (files.isEmpty()) {
+ // clear artifact references
+ template.setArtifactReferences(null);
+ } else {
+ ArtifactReferences artifactReferences = new ArtifactReferences();
+ template.setArtifactReferences(artifactReferences);
+ List<TArtifactReference> artRefList = artifactReferences.getArtifactReference();
+ for (RepositoryFileReference ref : files) {
+ // determine path
+ // path relative from the root of the CSAR is ok (COS01, line 2663)
+ String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref));
+
+ // put path into data structure
+ // we do not use Inlude/Exclude as we directly reference a concrete file
+ TArtifactReference artRef = new TArtifactReference();
+ artRef.setReference(path);
+ artRefList.add(artRef);
+ }
+ }
+ }
+
+ @Path("files/")
+ public FilesResource getFilesResource() {
+ ArtifactTemplateDirectoryId fileDir = new ArtifactTemplateDirectoryId((ArtifactTemplateId) this.id);
+ return new FilesResource(fileDir);
+ }
+
+ /***********************************************************************
+ * "inheritance" from TEntityTemplateResource<TArtifactTemplate> *
+ *
+ * Offering all methods of TEntityTemplateResource<TArtifactTemplate> and
+ * forwarding it to our private instance of it
+ */
+
+ @Override
+ public QName getType() {
+ return this.entityTemplateResource.getType();
+ }
+
+ @Override
+ public Response setType(QName type) {
+ this.entityTemplateResource.setType(type);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ public Response setType(String typeStr) {
+ this.entityTemplateResource.setType(typeStr);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ public PropertiesResource getPropertiesResource() {
+ return new PropertiesResource(this.getTArtifactTemplate(), this);
+ }
+
+ int getReferenceCount() {
+ // We do not use a database, therefore, we have to go through all possibilities pointing to the artifact template
+ // DAs and IAs point to an artifact template
+ // DAs are contained in Node Type Implementations and Node Templates
+ // IAs are contained in Node Type Implementations and Relationship Type Implementations
+
+ int count = 0;
+
+ Collection<TDeploymentArtifact> allDAs = new HashSet<>();
+ Collection<TImplementationArtifact> allIAs = new HashSet<>();
+
+ // handle Node Type Implementation, which contains DAs and IAs
+ SortedSet<NodeTypeImplementationId> nodeTypeImplementations = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeImplementationId.class);
+ for (NodeTypeImplementationId ntiId : nodeTypeImplementations) {
+ NodeTypeImplementationResource ntiRes = (NodeTypeImplementationResource) AbstractComponentsResource.getComponentInstaceResource(ntiId);
+ TDeploymentArtifacts deploymentArtifacts = ntiRes.getNTI().getDeploymentArtifacts();
+ if (deploymentArtifacts != null) {
+ allDAs.addAll(deploymentArtifacts.getDeploymentArtifact());
+ }
+ TImplementationArtifacts implementationArtifacts = ntiRes.getNTI().getImplementationArtifacts();
+ if (implementationArtifacts != null) {
+ allIAs.addAll(implementationArtifacts.getImplementationArtifact());
+ }
+ }
+
+ // check all Relationshiptype Implementations for IAs
+ SortedSet<RelationshipTypeImplementationId> relationshipTypeImplementations = Repository.INSTANCE.getAllTOSCAComponentIds(RelationshipTypeImplementationId.class);
+ for (RelationshipTypeImplementationId rtiId : relationshipTypeImplementations) {
+ RelationshipTypeImplementationResource rtiRes = (RelationshipTypeImplementationResource) AbstractComponentsResource.getComponentInstaceResource(rtiId);
+ TImplementationArtifacts implementationArtifacts = rtiRes.getRTI().getImplementationArtifacts();
+ if (implementationArtifacts != null) {
+ allIAs.addAll(implementationArtifacts.getImplementationArtifact());
+ }
+ }
+
+ // check all node templates for DAs
+ SortedSet<ServiceTemplateId> serviceTemplates = Repository.INSTANCE.getAllTOSCAComponentIds(ServiceTemplateId.class);
+ for (ServiceTemplateId sid : serviceTemplates) {
+ ServiceTemplateResource serviceTemplateRes = (ServiceTemplateResource) AbstractComponentsResource.getComponentInstaceResource(sid);
+ TTopologyTemplate topologyTemplate = serviceTemplateRes.getServiceTemplate().getTopologyTemplate();
+ if (topologyTemplate != null) {
+ List<TEntityTemplate> nodeTemplateOrRelationshipTemplate = topologyTemplate.getNodeTemplateOrRelationshipTemplate();
+ for (TEntityTemplate template : nodeTemplateOrRelationshipTemplate) {
+ if (template instanceof TNodeTemplate) {
+ TNodeTemplate nodeTemplate = (TNodeTemplate) template;
+ TDeploymentArtifacts deploymentArtifacts = nodeTemplate.getDeploymentArtifacts();
+ if (deploymentArtifacts != null) {
+ allDAs.addAll(deploymentArtifacts.getDeploymentArtifact());
+ }
+ }
+ }
+ }
+ }
+
+ // now we have all DAs and IAs
+
+ QName ourQName = this.getQName();
+
+ // check DAs for artifact templates
+ for (TDeploymentArtifact da : allDAs) {
+ QName artifactRef = da.getArtifactRef();
+ if (ourQName.equals(artifactRef)) {
+ count++;
+ }
+ }
+
+ // check IAs for artifact templates
+ for (TImplementationArtifact ia : allIAs) {
+ QName artifactRef = ia.getArtifactRef();
+ if (ourQName.equals(artifactRef)) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Query parameter {@code type}:<br />
+ * Returns the type of the artifact template
+ *
+ * Query parameter {@code referenceCount}:<br />
+ * Determines the number of elements known by the repository which point to
+ * this resource. This method probably can be moved up the type hierarchy.
+ * Currently, it is only required here by the topology modeler.
+ *
+ * @return the type of the artifact template OR the number of references
+ * pointing to this resource
+ */
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response getRefereneCount(@QueryParam("referenceCount") String referenceCount, @QueryParam("type") String type) {
+ if (referenceCount != null) {
+ String res = Integer.toString(this.getReferenceCount());
+ return Response.ok().entity(res).build();
+ } else if (type != null) {
+ String res = this.getType().toString();
+ return Response.ok().entity(res).build();
+ } else {
+ // we enforce the query parameter to be extensible to other queries
+ return Response.status(Status.BAD_REQUEST).entity("You have to pass the query parameter referenceCount or type").build();
+ }
+
+ }
+
+ /* not yet implemented */
+ /*
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getReferenes(@QueryParam("references") String references) {
+ if (references== null) {
+ // we enforce the query parameter to be extensible to other queries
+ return Response.status(Status.BAD_REQUEST).entity("You have to pass the query parameter references").build();
+ }
+
+ String res = Integer.toString(this.getReferenceCount());
+ return Response.ok().entity(res).build();
+ }
+ */
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java
new file mode 100644
index 0000000..e02a668
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/ArtifactTemplatesResource.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource;
+
+/**
+ * This class does NOT inherit from TEntityTemplatesResource<ArtifactTemplate>
+ * as these templates are directly nested in a TDefinitionsElement
+ */
+public class ArtifactTemplatesResource extends AbstractComponentsWithTypeReferenceResource<ArtifactTemplateResource> {
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java
new file mode 100644
index 0000000..0a910fe
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/artifacttemplates/FilesResource.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates.artifacttemplates;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.FileMeta;
+import org.eclipse.winery.repository.datatypes.ids.elements.ArtifactTemplateDirectoryId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+public class FilesResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(FilesResource.class);
+ private final ArtifactTemplateDirectoryId fileDir;
+
+
+ public FilesResource(ArtifactTemplateDirectoryId fileDir) {
+ this.fileDir = fileDir;
+ }
+
+ private String getData4jqueryFileUpload(List<FileMeta> metas) {
+ String data4jqueryFileUpload = Utils.Object2JSON(metas);
+ data4jqueryFileUpload = "{\"files\":" + data4jqueryFileUpload + "}";
+ return data4jqueryFileUpload;
+ }
+
+ /**
+ * Handles the upload of a <em>single</em> file. Adds the given file to the
+ * current artifact template.
+ *
+ * If the file already exists, is it <em>overridden</em>
+ *
+ * @return JSON with data required by JQuery-File-Upload (see
+ * https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
+ */
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response onPost(@FormDataParam("files[]") InputStream uploadedInputStream, @FormDataParam("files[]") FormDataContentDisposition fileDetail, @FormDataParam("files[]") FormDataBodyPart body, @Context UriInfo uriInfo) {
+ // existence check not required as instantiation of the resource ensures that the object only exists if the resource exists
+ FilesResource.logger.debug("Beginning with file upload");
+
+ String fileName = fileDetail.getFileName();
+ if (StringUtils.isEmpty(fileName)) {
+ return Response.status(Status.BAD_REQUEST).build();
+ }
+ RepositoryFileReference ref = this.fileName2fileRef(fileName, false);
+
+ // TODO: instead of fixing the media type, we could overwrite the browser's mediatype by using some user configuration
+ BufferedInputStream bis = new BufferedInputStream(uploadedInputStream);
+ MediaType mediaType = Utils.getFixedMimeType(bis, fileName, body.getMediaType());
+
+ Response response = BackendUtils.putContentToFile(ref, bis, mediaType);
+ if (response.getStatus() == Status.INTERNAL_SERVER_ERROR.getStatusCode()) {
+ return response;
+ }
+
+ // create FileMeta object
+ String URL = Utils.getAbsoluteURL(this.fileDir) + Util.URLencode(fileName);
+ String thumbnailURL = uriInfo.getBaseUriBuilder().path(Constants.PATH_MIMETYPEIMAGES).path(FilenameUtils.getExtension(fileName) + Constants.SUFFIX_MIMETYPEIMAGES).build().toString();
+ long size;
+ try {
+ size = Repository.INSTANCE.getSize(ref);
+ } catch (IOException e) {
+ FilesResource.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+ FileMeta fileMeta = new FileMeta(fileName, size, URL, thumbnailURL);
+
+ List<FileMeta> metas = new ArrayList<FileMeta>();
+ metas.add(fileMeta);
+ return Response.created(Utils.createURI(URL)).entity(this.getData4jqueryFileUpload(metas)).build();
+ }
+
+ /**
+ * Returns a list of file meta object
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public String getJSON() {
+ return this.getData4jqueryFileUpload(this.getAllFileMetas());
+ }
+
+ private List<FileMeta> getAllFileMetas() {
+ List<FileMeta> res = new ArrayList<FileMeta>();
+ SortedSet<RepositoryFileReference> fileRefs = Repository.INSTANCE.getContainedFiles(this.fileDir);
+ for (RepositoryFileReference ref : fileRefs) {
+ res.add(new FileMeta(ref));
+ }
+ return res;
+ }
+
+ private RepositoryFileReference fileName2fileRef(String fileName, boolean encoded) {
+ if (encoded) {
+ fileName = Util.URLdecode(fileName);
+ }
+ RepositoryFileReference ref = new RepositoryFileReference(this.fileDir, fileName);
+ return ref;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytemplates/artifacttemplates/files.jsp");
+ }
+
+ @GET
+ @Path("/{fileName}")
+ public Response getFile(@PathParam("fileName") String fileName, @HeaderParam("If-Modified-Since") String modified) {
+ RepositoryFileReference ref = this.fileName2fileRef(fileName, true);
+ return BackendUtils.returnRepoPath(ref, modified);
+ }
+
+ @DELETE
+ @Path("/{fileName}")
+ public Response deleteFile(@PathParam("fileName") String fileName) {
+ RepositoryFileReference ref = this.fileName2fileRef(fileName, true);
+ return BackendUtils.delete(ref);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java
new file mode 100644
index 0000000..4375378
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/package-info.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+/**
+ * The sub packages of this package contains all resources, which are derived
+ * from tEntityTemplate
+ *
+ * EntityTemplates get their namespaces from the surrounding
+ * Definitions-element. <br />
+ * Nevertheless, they are stored using the same filesystem structure as
+ * EntityTypes
+ *
+ * {@link org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.RelationshipTemplateResource}
+ * and
+ * {@link org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.NodeTemplateResource}
+ * are stored in the topology package
+ */
+package org.eclipse.winery.repository.resources.entitytemplates;
+
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java
new file mode 100644
index 0000000..e69a282
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplateResource.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates.policytemplates;
+
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TPolicyTemplate;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources.IHasName;
+import org.eclipse.winery.repository.resources.entitytemplates.IEntityTemplateResource;
+import org.eclipse.winery.repository.resources.entitytemplates.PropertiesResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class PolicyTemplateResource extends AbstractComponentInstanceResource implements IEntityTemplateResource<TPolicyTemplate>, IHasName {
+
+ private static final Logger logger = LoggerFactory.getLogger(PolicyTemplateResource.class);
+
+
+ /**
+ * Constructor has to be public because of test cases
+ */
+ public PolicyTemplateResource(PolicyTemplateId id) {
+ super(id);
+ }
+
+ /**
+ * Convenience method to avoid casting at the caller's side.
+ */
+ public TPolicyTemplate getPolicyTemplate() {
+ return (TPolicyTemplate) this.getElement();
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TPolicyTemplate();
+ }
+
+ @Override
+ public QName getType() {
+ return this.getPolicyTemplate().getType();
+ }
+
+ @Override
+ public Response setType(QName type) {
+ this.getPolicyTemplate().setType(type);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ public Response setType(String typeStr) {
+ this.getPolicyTemplate().setType(QName.valueOf(typeStr));
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ public PropertiesResource getPropertiesResource() {
+ return new PropertiesResource(this.getPolicyTemplate(), this);
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ this.getPolicyTemplate().setId(this.getId().getXmlId().getDecoded());
+ }
+
+ @Override
+ public String getName() {
+ String name = this.getPolicyTemplate().getName();
+ if (name == null) {
+ return this.getPolicyTemplate().getId();
+ } else {
+ return name;
+ }
+ }
+
+ @Override
+ public Response setName(String name) {
+ this.getPolicyTemplate().setName(name);
+ return BackendUtils.persist(this);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java
new file mode 100644
index 0000000..685ab66
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytemplates/policytemplates/PolicyTemplatesResource.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytemplates.policytemplates;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource;
+
+/**
+ * Manages all policy types in all available namespaces <br />
+ * The actual implementation is done in the
+ * AbstractComponentsWithTypeReferenceResource
+ */
+public class PolicyTemplatesResource extends AbstractComponentsWithTypeReferenceResource<PolicyTemplateResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java
new file mode 100644
index 0000000..8b48e74
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/EntityTypeImplementationResource.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypeimplementations;
+
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal;
+import org.eclipse.winery.repository.resources.IHasTypeReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class EntityTypeImplementationResource extends AbstractComponentInstanceResourceWithNameDerivedFromAbstractFinal implements IHasTypeReference {
+
+ private static final Logger logger = LoggerFactory.getLogger(EntityTypeImplementationResource.class);
+
+
+ protected EntityTypeImplementationResource(TOSCAComponentId id) {
+ super(id);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java
new file mode 100644
index 0000000..95b95d2
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationResource.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.model.tosca.TDeploymentArtifacts;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts;
+import org.eclipse.winery.model.tosca.TNodeTypeImplementation;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.artifacts.DeploymentArtifactsResource;
+import org.eclipse.winery.repository.resources.artifacts.ImplementationArtifactsResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource;
+
+public class NodeTypeImplementationResource extends EntityTypeImplementationResource implements INodeTemplateResourceOrNodeTypeImplementationResource, INodeTypeImplementationResourceOrRelationshipTypeImplementationResource {
+
+ public NodeTypeImplementationResource(NodeTypeImplementationId id) {
+ super(id);
+ }
+
+ /**
+ * public because of exporter
+ */
+ public TNodeTypeImplementation getNTI() {
+ return (TNodeTypeImplementation) this.getElement();
+ }
+
+ /**
+ * Even if both node type implementations and relationship type
+ * implementations have implementation artifacts, there is no common
+ * supertype. To avoid endless casts, we just implement the method here
+ *
+ * @return
+ */
+ @Path("implementationartifacts/")
+ public ImplementationArtifactsResource getImplementationArtifacts() {
+ TImplementationArtifacts implementationArtifacts;
+ implementationArtifacts = this.getNTI().getImplementationArtifacts();
+ if (implementationArtifacts == null) {
+ implementationArtifacts = new TImplementationArtifacts();
+ this.getNTI().setImplementationArtifacts(implementationArtifacts);
+ }
+ return new ImplementationArtifactsResource(implementationArtifacts.getImplementationArtifact(), this);
+ }
+
+ /**
+ * Only NodeTypes have deployment artifacts, not RelationshipType.
+ * Therefore, this method is declared in
+ * {@link NodeTypeImplementationResource} and not in
+ * {@link EntityTypeImplementationResource}
+ */
+ @Path("deploymentartifacts/")
+ public DeploymentArtifactsResource getDeploymentArtifacts() {
+ TDeploymentArtifacts deploymentArtifacts;
+ deploymentArtifacts = this.getNTI().getDeploymentArtifacts();
+ if (deploymentArtifacts == null) {
+ deploymentArtifacts = new TDeploymentArtifacts();
+ this.getNTI().setDeploymentArtifacts(deploymentArtifacts);
+ }
+ return new DeploymentArtifactsResource(deploymentArtifacts.getDeploymentArtifact(), this);
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TNodeTypeImplementation();
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ this.getNTI().setTargetNamespace(this.getId().getNamespace().getDecoded());
+ this.getNTI().setName(this.getId().getXmlId().getDecoded());
+ }
+
+ @Override
+ public QName getType() {
+ return this.getNTI().getNodeType();
+ }
+
+ @Override
+ public Response setType(QName type) {
+ this.getNTI().setNodeType(type);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ public Response setType(String typeStr) {
+ QName type = QName.valueOf(typeStr);
+ return this.setType(type);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java
new file mode 100644
index 0000000..b9c0836
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/nodetypeimplementations/NodeTypeImplementationsResource.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypeimplementations.nodetypeimplementations;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource;
+
+public class NodeTypeImplementationsResource extends AbstractComponentsWithTypeReferenceResource<NodeTypeImplementationResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java
new file mode 100644
index 0000000..af1c346
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/package-info.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+/**
+ * The sub packages of this package contains all resources, which are
+ * implementations of a type. <br />
+ * The specification does NOT introduce tEntityTypeImplementation, but we
+ * implement as if that had been happened.
+ */
+package org.eclipse.winery.repository.resources.entitytypeimplementations;
+
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java
new file mode 100644
index 0000000..521758a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationResource.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImplementationArtifacts;
+import org.eclipse.winery.model.tosca.TRelationshipTypeImplementation;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.INodeTypeImplementationResourceOrRelationshipTypeImplementationResource;
+import org.eclipse.winery.repository.resources.artifacts.ImplementationArtifactsResource;
+import org.eclipse.winery.repository.resources.entitytypeimplementations.EntityTypeImplementationResource;
+
+public class RelationshipTypeImplementationResource extends EntityTypeImplementationResource implements INodeTypeImplementationResourceOrRelationshipTypeImplementationResource {
+
+ public RelationshipTypeImplementationResource(RelationshipTypeImplementationId id) {
+ super(id);
+ }
+
+ public TRelationshipTypeImplementation getRTI() {
+ return (TRelationshipTypeImplementation) this.getElement();
+ }
+
+ /**
+ * Even if both node type implementations and relationship type
+ * implementations have implementation artifacts, there is no common
+ * supertype. To avoid endless casts, we just implement the method here
+ */
+ @Path("implementationartifacts/")
+ public ImplementationArtifactsResource getImplementationArtifacts() {
+ TImplementationArtifacts implementationArtifacts;
+ implementationArtifacts = this.getRTI().getImplementationArtifacts();
+ if (implementationArtifacts == null) {
+ implementationArtifacts = new TImplementationArtifacts();
+ this.getRTI().setImplementationArtifacts(implementationArtifacts);
+ }
+ return new ImplementationArtifactsResource(implementationArtifacts.getImplementationArtifact(), this);
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TRelationshipTypeImplementation();
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ this.getRTI().setTargetNamespace(this.getId().getNamespace().getDecoded());
+ this.getRTI().setName(this.getId().getXmlId().getDecoded());
+ }
+
+ @Override
+ public QName getType() {
+ return this.getRTI().getRelationshipType();
+ }
+
+ @Override
+ public Response setType(QName type) {
+ this.getRTI().setRelationshipType(type);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ public Response setType(String typeStr) {
+ QName qname = QName.valueOf(typeStr);
+ return this.setType(qname);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java
new file mode 100644
index 0000000..f503a6f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypeimplementations/relationshiptypeimplementations/RelationshipTypeImplementationsResource.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypeimplementations.relationshiptypeimplementations;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsWithTypeReferenceResource;
+
+public class RelationshipTypeImplementationsResource extends AbstractComponentsWithTypeReferenceResource<RelationshipTypeImplementationResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java
new file mode 100644
index 0000000..5f4d06e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/ImplementationsOfOneType.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes;
+
+import java.util.Collection;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.definitions.TopologyGraphElementEntityTypeId;
+import org.eclipse.winery.repository.resources.admin.NamespacesResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * specifies the methods required by implementations.jsp
+ */
+public abstract class ImplementationsOfOneType {
+
+ private final TopologyGraphElementEntityTypeId typeId;
+
+
+ public ImplementationsOfOneType(TopologyGraphElementEntityTypeId typeId) {
+ this.typeId = typeId;
+ }
+
+ public TopologyGraphElementEntityTypeId getTypeId() {
+ return this.typeId;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML() {
+ Viewable viewable = new Viewable("/jsp/entitytypes/implementations.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public abstract Response getJSON();
+
+ public Collection<Namespace> getNamespaceAutocompletionList() {
+ return NamespacesResource.getNamespaces();
+ }
+
+ /**
+ * @return a list of type implementations implementing the associated node
+ * type
+ */
+ public abstract String getImplementationsTableData();
+
+ /**
+ * The string used as URL part
+ */
+ public abstract String getType();
+
+ /**
+ * The string displayed to the user
+ */
+ public abstract String getTypeStr();
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java
new file mode 100644
index 0000000..4eaea1c
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/InstanceStatesResource.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates;
+import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates.InstanceState;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.backend.BackendUtils;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Resource for instance states <br />
+ * Used by relationship types and node types
+ */
+public class InstanceStatesResource {
+
+ private TopologyGraphElementEntityTypeResource typeResource;
+ private TTopologyElementInstanceStates instanceStates;
+
+
+ /**
+ *
+ * @param instanceStates the instanceStates to manage
+ * @param typeResource the type resource, where the instance states are
+ * managed. This reference is required to fire "persist()" in
+ * case of updates
+ */
+ public InstanceStatesResource(TTopologyElementInstanceStates instanceStates, TopologyGraphElementEntityTypeResource typeResource) {
+ this.instanceStates = instanceStates;
+ this.typeResource = typeResource;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/instancestates.jsp", this);
+ }
+
+ public List<String> getInstanceStates() {
+ List<InstanceState> instanceStates = this.instanceStates.getInstanceState();
+ ArrayList<String> states = new ArrayList<String>(instanceStates.size());
+ for (InstanceState instanceState : instanceStates) {
+ states.add(instanceState.getState());
+ }
+ return states;
+ }
+
+ @DELETE
+ @Path("{instanceState}")
+ public Response deleteInstanceState(@PathParam("instanceState") String instanceStateToRemove) {
+ if (StringUtils.isEmpty(instanceStateToRemove)) {
+ return Response.status(Status.BAD_REQUEST).entity("null instance to remove").build();
+ }
+ instanceStateToRemove = Util.URLdecode(instanceStateToRemove);
+
+ // InstanceState does not override "equals()", therefore we have to manually remove it
+
+ List<InstanceState> instanceStates = this.instanceStates.getInstanceState();
+ Iterator<InstanceState> iterator = instanceStates.iterator();
+ boolean found = false;
+ while (iterator.hasNext() && !found) {
+ if (iterator.next().getState().equals(instanceStateToRemove)) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+
+ iterator.remove();
+
+ return BackendUtils.persist(this.typeResource);
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response addInstanceState(@FormParam("state") String state) {
+ if (StringUtils.isEmpty(state)) {
+ return Response.notAcceptable(null).build();
+ }
+
+ // InstanceState does not override "equals()", therefore we have to manually check for existance
+
+ List<InstanceState> instanceStates = this.instanceStates.getInstanceState();
+ Iterator<InstanceState> iterator = instanceStates.iterator();
+ boolean found = false;
+ while (iterator.hasNext() && !found) {
+ if (iterator.next().getState().equals(state)) {
+ found = true;
+ }
+ }
+
+ if (found) {
+ // no error, just return
+ return Response.noContent().build();
+ }
+
+ InstanceState instanceState = new InstanceState();
+ instanceState.setState(state);
+ instanceStates.add(instanceState);
+
+ return BackendUtils.persist(this.typeResource);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java
new file mode 100644
index 0000000..6cebfe8
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/TopologyGraphElementEntityTypeResource.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes;
+
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+
+public abstract class TopologyGraphElementEntityTypeResource extends EntityTypeResource {
+
+ protected TopologyGraphElementEntityTypeResource(TOSCAComponentId id) {
+ super(id);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java
new file mode 100644
index 0000000..232d4f9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypeResource.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.artifacttypes;
+
+import java.util.SortedSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.constants.Namespaces;
+import org.eclipse.winery.common.ids.definitions.ArtifactTemplateId;
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.model.tosca.TArtifactType;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+
+public class ArtifactTypeResource extends EntityTypeResource {
+
+ public ArtifactTypeResource(ArtifactTypeId id) {
+ super(id);
+ }
+
+
+ private final QName qnameFileExtension = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "fileExtension");
+
+
+ /**
+ * @return the file extension associated with this artifact type. May be
+ * null
+ */
+ @GET
+ @Path("/fileextension")
+ public String getAssociatedFileExtension() {
+ return this.getDefinitions().getOtherAttributes().get(this.qnameFileExtension);
+ }
+
+ @PUT
+ @Path("/fileextension")
+ public Response setAssociatedFileExtension(String fileExtension) {
+ this.getDefinitions().getOtherAttributes().put(this.qnameFileExtension, fileExtension);
+ return BackendUtils.persist(this);
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TArtifactType();
+ }
+
+ @Override
+ public SortedSet<Select2OptGroup> getListOfAllInstances() {
+ return this.getListOfAllInstances(ArtifactTemplateId.class);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java
new file mode 100644
index 0000000..b52aa31
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/artifacttypes/ArtifactTypesResource.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.artifacttypes;
+
+import java.util.SortedSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.ids.definitions.ArtifactTypeId;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+public class ArtifactTypesResource extends AbstractComponentsResource<ArtifactTypeResource> {
+
+ // This cannot be used as the INSTANCE is per startup of the whole
+ // application
+ // We could do some checking for the number of ArtifactTypeResources or
+ // timestamp,
+ //
+ // private final HashMap<String, ArtifactTypeResource> fileExtensionMapping
+ // = new ArtifactTypesResource().getFileExtensionMapping();
+
+ /**
+ * @return a mapping from file extension to artifact type resources
+ */
+ // public HashMap<String, ArtifactTypeResource> getFileExtensionMapping() {
+ // HashMap<String, ArtifactTypeResource> res = new HashMap<String,
+ // ArtifactTypeResource>();
+ // for (ArtifactTypeResource at : this.getArtifactTypeResources()) {
+ // if (at.getAssociatedFileExtension() != null) {
+ // res.put(at.getAssociatedFileExtension(), at);
+ // }
+ // }
+ // return res;
+ // }
+
+ @GET
+ // should be "QName", but that MIME type is not available. XLink is too
+ // complicated for our setup
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response getArtifactTypeQNameForExtension(@QueryParam("extension") String extension) {
+ if (extension == null) {
+ return Response.status(Status.NOT_ACCEPTABLE).build();
+ }
+ ArtifactTypeResource artifactType = this.getArtifactTypeForExtension(extension);
+ Response res;
+ if (artifactType == null) {
+ res = Response.status(Status.NOT_FOUND).build();
+ } else {
+ res = Response.ok().entity(artifactType.getId().getQName().toString()).build();
+ }
+ return res;
+ }
+
+ /**
+ * Returns the first matching ArtifactTypeResource for the given file
+ * extension. Returns null if no such ArtifactType can be found
+ *
+ * The case of the extension is ignored.
+ *
+ * This is more a DAO method
+ */
+ public ArtifactTypeResource getArtifactTypeForExtension(String extension) {
+ SortedSet<ArtifactTypeId> allArtifactTypeIds = Repository.INSTANCE.getAllTOSCAComponentIds(ArtifactTypeId.class);
+ ArtifactTypeResource res = null;
+ for (ArtifactTypeId id : allArtifactTypeIds) {
+ ArtifactTypeResource r = new ArtifactTypeResource(id);
+ if (extension.equalsIgnoreCase(r.getAssociatedFileExtension())) {
+ res = r;
+ break;
+ }
+ }
+ return res;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java
new file mode 100644
index 0000000..924efd4
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypeResource.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.capabilitytypes;
+
+import org.eclipse.winery.model.tosca.TCapabilityType;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class CapabilityTypeResource extends EntityTypeResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(CapabilityTypeResource.class);
+
+
+ /**
+ * Constructor has to be public because of test cases
+ */
+ public CapabilityTypeResource(CapabilityTypeId id) {
+ super(id);
+ }
+
+ /**
+ * Convenience method to avoid casting at the caller's side.
+ *
+ * @return the CapabilityType object this resource is representing
+ */
+ public TCapabilityType getCapabilityType() {
+ return (TCapabilityType) this.getElement();
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TCapabilityType();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java
new file mode 100644
index 0000000..a34aac2
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/capabilitytypes/CapabilityTypesResource.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.capabilitytypes;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+/**
+ * Manages all capability types in all available namespaces <br />
+ * The actual implementation is done in the AbstractComponentsResource
+ */
+public class CapabilityTypesResource extends AbstractComponentsResource<CapabilityTypeResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java
new file mode 100644
index 0000000..63d483d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/ImplementationsOfOneNodeTypeResource.java
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.NodeTypeImplementationId;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.entitytypes.ImplementationsOfOneType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+public class ImplementationsOfOneNodeTypeResource extends ImplementationsOfOneType {
+
+ private static final Logger logger = LoggerFactory.getLogger(ImplementationsOfOneNodeTypeResource.class);
+
+
+ /**
+ * The constructor is different from the usual constructors as this resource
+ * does NOT store own data, but retrieves its data solely from the
+ * associated node type
+ *
+ * @param nodeTypeId the node type id, where this list of implementations
+ * belongs to
+ */
+ public ImplementationsOfOneNodeTypeResource(NodeTypeId nodeTypeId) {
+ super(nodeTypeId);
+ }
+
+ /**
+ * required by implementations.jsp
+ *
+ * @return for each node type implementation implementing the associated
+ * node type
+ */
+ @Override
+ public String getImplementationsTableData() {
+ String res;
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter tableDataSW = new StringWriter();
+ try {
+ JsonGenerator jGenerator = jsonFactory.createGenerator(tableDataSW);
+ jGenerator.writeStartArray();
+
+ Collection<NodeTypeImplementationId> allNodeTypeImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, this.getTypeId().getQName());
+ for (NodeTypeImplementationId ntiID : allNodeTypeImplementations) {
+ jGenerator.writeStartArray();
+ jGenerator.writeString(ntiID.getNamespace().getDecoded());
+ jGenerator.writeString(ntiID.getXmlId().getDecoded());
+ jGenerator.writeEndArray();
+ }
+ jGenerator.writeEndArray();
+ jGenerator.close();
+ tableDataSW.close();
+ res = tableDataSW.toString();
+ } catch (Exception e) {
+ ImplementationsOfOneNodeTypeResource.logger.error(e.getMessage(), e);
+ res = "[]";
+ }
+ return res;
+ }
+
+ @Override
+ public String getType() {
+ return "nodetype";
+ }
+
+ @Override
+ public String getTypeStr() {
+ return "Node Type";
+ }
+
+ @Override
+ public Response getJSON() {
+ Collection<NodeTypeImplementationId> allImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(NodeTypeImplementationId.class, this.getTypeId().getQName());
+ ArrayList<QName> res = new ArrayList<QName>(allImplementations.size());
+ for (NodeTypeImplementationId id : allImplementations) {
+ res.add(id.getQName());
+ }
+ return Response.ok().entity(res).build();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java
new file mode 100644
index 0000000..6c573a5
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypeResource.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes;
+
+import javax.ws.rs.Path;
+
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TNodeType;
+import org.eclipse.winery.model.tosca.TNodeType.CapabilityDefinitions;
+import org.eclipse.winery.model.tosca.TNodeType.Interfaces;
+import org.eclipse.winery.model.tosca.TNodeType.RequirementDefinitions;
+import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.repository.resources.entitytypes.InstanceStatesResource;
+import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs.CapabilityDefinitionsResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs.RequirementDefinitionsResource;
+import org.eclipse.winery.repository.resources.interfaces.InterfacesResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NodeTypeResource extends TopologyGraphElementEntityTypeResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(NodeTypeResource.class);
+
+
+ public NodeTypeResource(NodeTypeId id) {
+ super(id);
+ }
+
+ /**
+ * Convenience method to avoid casting at the caller's side.
+ */
+ public TNodeType getNodeType() {
+ return (TNodeType) this.getElement();
+ }
+
+ /** sub-resources **/
+
+ @Path("implementations/")
+ public ImplementationsOfOneNodeTypeResource getImplementations() {
+ return new ImplementationsOfOneNodeTypeResource((NodeTypeId) this.id);
+ }
+
+ @Path("instancestates/")
+ public InstanceStatesResource getInstanceStatesResource() {
+ TTopologyElementInstanceStates instanceStates = this.getNodeType().getInstanceStates();
+ if (instanceStates == null) {
+ // if an explicit (empty) list does not exist, create it
+ instanceStates = new TTopologyElementInstanceStates();
+ this.getNodeType().setInstanceStates(instanceStates);
+ }
+ return new InstanceStatesResource(instanceStates, this);
+ }
+
+ @Path("interfaces/")
+ public InterfacesResource getInterfaces() {
+ Interfaces interfaces = this.getNodeType().getInterfaces();
+ if (interfaces == null) {
+ interfaces = new Interfaces();
+ this.getNodeType().setInterfaces(interfaces);
+ }
+ return new InterfacesResource(null, interfaces.getInterface(), this);
+ }
+
+ @Path("requirementdefinitions/")
+ public RequirementDefinitionsResource getRequirementDefinitions() {
+ RequirementDefinitions definitions = this.getNodeType().getRequirementDefinitions();
+ if (definitions == null) {
+ definitions = new RequirementDefinitions();
+ this.getNodeType().setRequirementDefinitions(definitions);
+ }
+ return new RequirementDefinitionsResource(this, definitions.getRequirementDefinition());
+ }
+
+ @Path("capabilitydefinitions/")
+ public CapabilityDefinitionsResource getCapabilityDefinitions() {
+ CapabilityDefinitions definitions = this.getNodeType().getCapabilityDefinitions();
+ if (definitions == null) {
+ definitions = new CapabilityDefinitions();
+ this.getNodeType().setCapabilityDefinitions(definitions);
+ }
+ return new CapabilityDefinitionsResource(this, definitions.getCapabilityDefinition());
+ }
+
+ @Path("visualappearance/")
+ public VisualAppearanceResource getVisualAppearanceResource() {
+ return new VisualAppearanceResource(this, this.getElement().getOtherAttributes(), (NodeTypeId) this.id);
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TNodeType();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java
new file mode 100644
index 0000000..798e5a5
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/NodeTypesResource.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+/**
+ * Manages all nodetypes in all available namespaces <br />
+ * The actual implementation is done in the AbstractComponentsResource
+ */
+public class NodeTypesResource extends AbstractComponentsResource<NodeTypeResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java
new file mode 100644
index 0000000..d897efe
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/VisualAppearanceResource.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.constants.QNames;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.constants.Filename;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.resources.GenericVisualAppearanceResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+public class VisualAppearanceResource extends GenericVisualAppearanceResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(VisualAppearanceResource.class);
+
+
+ public VisualAppearanceResource(NodeTypeResource res, Map<QName, String> map, NodeTypeId parentId) {
+ super(res, map, new VisualAppearanceId(parentId));
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML() {
+ Viewable viewable = new Viewable("/jsp/entitytypes/nodetypes/visualappearance.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+
+ @GET
+ @Path("50x50")
+ public Response get50x50Image(@HeaderParam("If-Modified-Since") String modified) {
+ return this.getImage(Filename.FILENAME_BIG_ICON, modified);
+ }
+
+ @PUT
+ @Path("50x50")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response post50x50Image(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) {
+ return this.putImage(Filename.FILENAME_BIG_ICON, uploadedInputStream, body.getMediaType());
+ }
+
+ @GET
+ @Path("bordercolor")
+ public String getBorderColor() {
+ return BackendUtils.getColorAndSetDefaultIfNotExisting(this.getId().getParent().getXmlId().getDecoded(), QNames.QNAME_BORDER_COLOR, this.otherAttributes, this.res);
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Path("bordercolor")
+ public Response putBorderColor(@FormParam("color") String color) {
+ this.otherAttributes.put(QNames.QNAME_BORDER_COLOR, color);
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java
new file mode 100644
index 0000000..b7eea92
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/AbstractReqOrCapDefResource.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.model.tosca.TCapabilityDefinition;
+import org.eclipse.winery.model.tosca.TConstraint;
+import org.eclipse.winery.model.tosca.TRequirementDefinition;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.ConstraintsResource;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Bundles common properties of TRequirementDefinition and TCapabilityDefinition
+ *
+ * We agreed in the project not to modify org.eclipse.winery.model.tosca.
+ * Therefore, this resource models the common properties of a
+ * TRequirementDefinition and a TCapabilityDefinition
+ */
+public abstract class AbstractReqOrCapDefResource<ReqOrCapDef> extends EntityWithIdResource<ReqOrCapDef> implements IIdDetermination<ReqOrCapDef> {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractReqOrCapDefResource.class);
+
+ protected NodeTypeResource parent;
+
+ // the capability or the requirement
+ private Object reqOrCapDef;
+
+ private List<TConstraint> constraints;
+
+
+ /**
+ * @param constraints additional parameter (in comparison to the constructor
+ * of EntityWithIdResource) as we require that sublist for the
+ * constrinats sub resource
+ */
+ public AbstractReqOrCapDefResource(IIdDetermination<ReqOrCapDef> idDetermination, ReqOrCapDef reqOrCapDef, int idx, List<ReqOrCapDef> list, NodeTypeResource res, List<TConstraint> constraints) {
+ super(idDetermination, reqOrCapDef, idx, list, res);
+ assert ((reqOrCapDef instanceof TRequirementDefinition) || (reqOrCapDef instanceof TCapabilityDefinition));
+ this.parent = res;
+ this.reqOrCapDef = reqOrCapDef;
+ this.constraints = constraints;
+ }
+
+ @GET
+ @Path("name")
+ public String getName() {
+ return (String) this.invokeGetter("getName");
+ }
+
+ static String getName(Object reqOrCapDef) {
+ return (String) AbstractReqOrCapDefResource.invokeGetter(reqOrCapDef, "getName");
+ }
+
+ @GET
+ @Path("lowerbound")
+ public int getLowerBound() {
+ return (int) this.invokeGetter("getLowerBound");
+ }
+
+ @GET
+ @Path("upperbound")
+ public String getUpperBound() {
+ return (String) this.invokeGetter("getUpperBound");
+ }
+
+ @PUT
+ @Path("name")
+ public Response setName(@FormParam(value = "name") String name) {
+ // TODO: type check - see also min/max Instance of a node template
+ this.invokeSetter("setName", name);
+ return BackendUtils.persist(this.parent);
+ }
+
+ @PUT
+ @Path("lowerbound")
+ public Response setLowerBound(@FormParam(value = "lowerbound") String value) {
+ // TODO: type check
+ this.invokeSetter("setLowerBound", value);
+ return BackendUtils.persist(this.parent);
+ }
+
+ @PUT
+ @Path("upperbound")
+ public Response setUpperBound(@FormParam(value = "upperbound") String value) {
+ // TODO: type check
+ this.invokeSetter("setUpperBound", value);
+ return BackendUtils.persist(this.parent);
+ }
+
+ @Path("constraints/")
+ public ConstraintsResource getConstraintsResource() {
+ return new ConstraintsResource(this.constraints, this.parent);
+ }
+
+ private static Object invokeGetter(Object reqOrCapDef, String getterName) {
+ Method method;
+ Object res;
+ try {
+ method = reqOrCapDef.getClass().getMethod(getterName);
+ res = method.invoke(reqOrCapDef);
+ } catch (Exception e) {
+ AbstractReqOrCapDefResource.logger.error("Could not invoke getter {}", getterName, e);
+ throw new IllegalStateException(e);
+ }
+ return res;
+ }
+
+ private Object invokeGetter(String getterName) {
+ return AbstractReqOrCapDefResource.invokeGetter(this.reqOrCapDef, getterName);
+ }
+
+ /**
+ * Quick hack method for RequirementOrCapabilityDefinitionsResource
+ */
+ static void invokeSetter(Object reqOrCapDef, String setterName, Object value) {
+ Method method;
+ try {
+ method = reqOrCapDef.getClass().getMethod(setterName, value.getClass());
+ method.invoke(reqOrCapDef, value);
+ } catch (Exception e) {
+ AbstractReqOrCapDefResource.logger.error("Could not invoke setter {}", setterName, e);
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private void invokeSetter(String setterName, Object value) {
+ AbstractReqOrCapDefResource.invokeSetter(this.reqOrCapDef, setterName, value);
+ }
+
+ @GET
+ @Path("type")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getTypeAsString() {
+ return this.getType().toString();
+ }
+
+ /**
+ * required by the JSP.
+ *
+ * Therefore, we have two getters for the type: QName for the JSP and String
+ * for REST clients
+ */
+ public abstract QName getType();
+
+ /**
+ * Required by reqandcapdefs.jsp
+ */
+ public Object getDef() {
+ return this.reqOrCapDef;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java
new file mode 100644
index 0000000..0fd3bd3
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionResource.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs;
+
+import java.util.List;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.model.tosca.TCapabilityDefinition;
+import org.eclipse.winery.model.tosca.TCapabilityDefinition.Constraints;
+import org.eclipse.winery.model.tosca.TConstraint;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+
+/**
+ * Implementation similar to RequirementDefinitionResource, but with
+ * TCapabilityDefinition instead of TRequirementDefinition
+ */
+public final class CapabilityDefinitionResource extends AbstractReqOrCapDefResource<TCapabilityDefinition> {
+
+ private TCapabilityDefinition capDef;
+
+
+ /**
+ * Constructor has to follow the pattern of EnetityTResource as the
+ * constructor is invoked by reflection in EntityWithIdcollectionResource
+ *
+ * @param res the resource this req def is nested in. Has to be of Type
+ * "NodeTypeResource". Due to the implementation of
+ * org.eclipse.winery .repository.resources._support.collections.
+ * withid.EntityWithIdCollectionResource
+ * .getEntityResourceInstance(EntityT, int), we have to use
+ * "AbstractComponentInstanceResource" as type
+ */
+ public CapabilityDefinitionResource(IIdDetermination<TCapabilityDefinition> idDetermination, TCapabilityDefinition capDef, int idx, List<TCapabilityDefinition> list, AbstractComponentInstanceResource res) {
+ super(idDetermination, capDef, idx, list, (NodeTypeResource) res, CapabilityDefinitionResource.getConstraints(capDef));
+ this.capDef = capDef;
+ }
+
+ /**
+ * Quick hack to avoid internal server error
+ */
+ public CapabilityDefinitionResource(IIdDetermination<TCapabilityDefinition> idDetermination, TCapabilityDefinition capDef, int idx, List<TCapabilityDefinition> list, IPersistable res) {
+ this(idDetermination, capDef, idx, list, (AbstractComponentInstanceResource) res);
+ }
+
+ /**
+ * Fetch the list of constraints from the given definition. If the list does
+ * not exist, the list is created an stored in the given capDef
+ */
+ public static List<TConstraint> getConstraints(TCapabilityDefinition capDef) {
+ Constraints constraints = capDef.getConstraints();
+ if (constraints == null) {
+ constraints = new Constraints();
+ capDef.setConstraints(constraints);
+ }
+ return constraints.getConstraint();
+ }
+
+ public QName getType() {
+ return this.capDef.getCapabilityType();
+ }
+
+ @PUT
+ @Path("type")
+ public Response setType(@FormParam(value = "type") String value) {
+ QName qname = QName.valueOf(value);
+ this.capDef.setCapabilityType(qname);
+ return BackendUtils.persist(this.parent);
+ }
+
+ @Override
+ public String getId(TCapabilityDefinition e) {
+ return e.getName();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java
new file mode 100644
index 0000000..d93edb4
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/CapabilityDefinitionsResource.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
+import org.eclipse.winery.model.tosca.TCapabilityDefinition;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class CapabilityDefinitionsResource extends RequirementOrCapabilityDefinitionsResource<CapabilityDefinitionResource, TCapabilityDefinition> {
+
+ private static final Logger logger = LoggerFactory.getLogger(CapabilityDefinitionsResource.class);
+
+
+ public CapabilityDefinitionsResource(NodeTypeResource res, List<TCapabilityDefinition> defs) {
+ super(CapabilityDefinitionResource.class, TCapabilityDefinition.class, defs, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/nodetypes/reqandcapdefs/capdefs.jsp", this);
+ }
+
+ @Override
+ public Collection<QName> getAllTypes() {
+ SortedSet<CapabilityTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(CapabilityTypeId.class);
+ return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java
new file mode 100644
index 0000000..aeee000
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionResource.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs;
+
+import java.util.List;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.model.tosca.TConstraint;
+import org.eclipse.winery.model.tosca.TRequirementDefinition;
+import org.eclipse.winery.model.tosca.TRequirementDefinition.Constraints;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+
+public final class RequirementDefinitionResource extends AbstractReqOrCapDefResource<TRequirementDefinition> {
+
+ private TRequirementDefinition reqDef;
+
+
+ /**
+ * Constructor has to follow the pattern of EnetityTResource as the
+ * constructor is invoked by reflection in EntityWithIdcollectionResource
+ *
+ * @param res the resource this req def is nested in. Has to be of Type
+ * "NodeTypeResource". Due to the implementation of
+ * org.eclipse.winery .repository.resources._support.collections.
+ * withid.EntityWithIdCollectionResource
+ * .getEntityResourceInstance(EntityT, int), we have to use
+ * "AbstractComponentInstanceResource" as type
+ */
+ public RequirementDefinitionResource(IIdDetermination<TRequirementDefinition> idDetermination, TRequirementDefinition reqDef, int idx, List<TRequirementDefinition> list, AbstractComponentInstanceResource res) {
+ super(idDetermination, reqDef, idx, list, (NodeTypeResource) res, RequirementDefinitionResource.getConstraints(reqDef));
+ this.reqDef = reqDef;
+ }
+
+ /**
+ * Quick fix to avoid internal server error when opening
+ * RequirementDefinitions Tab
+ */
+ public RequirementDefinitionResource(IIdDetermination<TRequirementDefinition> idDetermination, TRequirementDefinition reqDef, int idx, List<TRequirementDefinition> list, IPersistable res) {
+ this(idDetermination, reqDef, idx, list, (AbstractComponentInstanceResource) res);
+ }
+
+ /**
+ * Fetch the list of constraints from the given definition. If the list does
+ * not exist, the list is created an stored in the given def
+ */
+ public static List<TConstraint> getConstraints(TRequirementDefinition def) {
+ Constraints constraints = def.getConstraints();
+ if (constraints == null) {
+ constraints = new Constraints();
+ def.setConstraints(constraints);
+ }
+ return constraints.getConstraint();
+ }
+
+ public QName getType() {
+ return this.reqDef.getRequirementType();
+ }
+
+ @PUT
+ @Path("type")
+ public Response setType(@FormParam(value = "type") String value) {
+ QName qname = QName.valueOf(value);
+ this.reqDef.setRequirementType(qname);
+ return BackendUtils.persist(this.parent);
+ }
+
+ @Override
+ public String getId(TRequirementDefinition e) {
+ return e.getName();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java
new file mode 100644
index 0000000..62db596
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementDefinitionsResource.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.RequirementTypeId;
+import org.eclipse.winery.model.tosca.TRequirementDefinition;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class RequirementDefinitionsResource extends RequirementOrCapabilityDefinitionsResource<RequirementDefinitionResource, TRequirementDefinition> {
+
+ public RequirementDefinitionsResource(NodeTypeResource res, List<TRequirementDefinition> defs) {
+ super(RequirementDefinitionResource.class, TRequirementDefinition.class, defs, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/nodetypes/reqandcapdefs/reqdefs.jsp", this);
+ }
+
+ @Override
+ public Collection<QName> getAllTypes() {
+ SortedSet<RequirementTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(RequirementTypeId.class);
+ return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java
new file mode 100644
index 0000000..0c6936e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/nodetypes/reqandcapdefs/RequirementOrCapabilityDefinitionsResource.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.nodetypes.reqandcapdefs;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.model.tosca.TCapabilityDefinition;
+import org.eclipse.winery.model.tosca.TRequirementDefinition;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.eclipse.winery.repository.resources.entitytypes.nodetypes.NodeTypeResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * This superclass has only a few methods as we cannot easily abstract from the
+ * subclasses: We would need Java reflection to invoke "getName" (to get the
+ * subresource). The hope is that this copy'n'paste programming will not
+ * introduce bugs when changing childs
+ *
+ * We try to abstract from the problems by using generics and reflections
+ *
+ * @param <ReqDefOrCapDef> TRequirementDefinition or TCapabilityDefinition
+ * @param <ReqDefOrCapDefResource> the resource managing ReqDefOrCapDef
+ */
+public abstract class RequirementOrCapabilityDefinitionsResource<ReqDefOrCapDefResource extends AbstractReqOrCapDefResource<ReqDefOrCapDef>, ReqDefOrCapDef> extends EntityWithIdCollectionResource<ReqDefOrCapDefResource, ReqDefOrCapDef> {
+
+ protected final NodeTypeResource res;
+
+
+ public RequirementOrCapabilityDefinitionsResource(Class<ReqDefOrCapDefResource> entityResourceTClazz, Class<ReqDefOrCapDef> entityTClazz, List<ReqDefOrCapDef> list, NodeTypeResource res) {
+ super(entityResourceTClazz, entityTClazz, list, res);
+ this.res = res;
+ }
+
+ @Override
+ public abstract Viewable getHTML();
+
+ /**
+ * @return collection of all available types
+ */
+ public abstract Collection<QName> getAllTypes();
+
+ @POST
+ // As there is no supertype of TCapabilityType and TRequirementType containing the common attributes, we have to rely on unchecked casts
+ @SuppressWarnings("unchecked")
+ public Response onPost(@FormParam("name") String name, @FormParam("type") String type, @FormParam("lowerbound") String lowerBound, @FormParam("upperbound") String upperbound) {
+ if (StringUtils.isEmpty(name)) {
+ return Response.status(Status.BAD_REQUEST).entity("Name has to be provided").build();
+ }
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).entity("Type has to be provided").build();
+ }
+
+ int lbound = 1;
+ if (!StringUtils.isEmpty(lowerBound)) {
+ try {
+ lbound = Integer.parseInt(lowerBound);
+ } catch (NumberFormatException e) {
+ return Response.status(Status.BAD_REQUEST).entity("Bad format of lowerbound: " + e.getMessage()).build();
+ }
+ }
+
+ String ubound = "1";
+ if (!StringUtils.isEmpty(upperbound)) {
+ ubound = upperbound;
+ }
+
+ // we also support replacement of existing requirements
+ // therefore, we loop through the existing requirements
+ int idx = -1;
+ boolean found = false;
+ for (ReqDefOrCapDef d : this.list) {
+ idx++;
+ if (this.getId(d).equals(name)) {
+ found = true;
+ break;
+ }
+ }
+
+ QName typeQName = QName.valueOf(type);
+ // Create object and put type in it
+ ReqDefOrCapDef def;
+ if (this instanceof CapabilityDefinitionsResource) {
+ def = (ReqDefOrCapDef) new TCapabilityDefinition();
+ ((TCapabilityDefinition) def).setCapabilityType(typeQName);
+ } else {
+ assert (this instanceof RequirementDefinitionsResource);
+ def = (ReqDefOrCapDef) new TRequirementDefinition();
+ ((TRequirementDefinition) def).setRequirementType(typeQName);
+ }
+
+ // copy all other data into object
+ AbstractReqOrCapDefResource.invokeSetter(def, "setName", name);
+ AbstractReqOrCapDefResource.invokeSetter(def, "setLowerBound", lbound);
+ AbstractReqOrCapDefResource.invokeSetter(def, "setUpperBound", ubound);
+
+ if (found) {
+ // replace element
+ this.list.set(idx, def);
+ } else {
+ // add new element
+ this.list.add(def);
+ }
+
+ Response r = BackendUtils.persist(this.res);
+ return r;
+ }
+
+ @Override
+ public String getId(ReqDefOrCapDef reqDefOrCapDef) {
+ return AbstractReqOrCapDefResource.getName(reqDefOrCapDef);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java
new file mode 100644
index 0000000..6fbbc5a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/package-info.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+/**
+ * The sub packages of this package contains all resources, which are derived
+ * from tEntityType
+ */
+package org.eclipse.winery.repository.resources.entitytypes;
+
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java
new file mode 100644
index 0000000..0e4b560
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/AppliesToResource.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.policytypes;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.model.tosca.TPolicyType;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class AppliesToResource {
+
+ private PolicyTypeResource policyTypeResource;
+
+
+ public AppliesToResource(PolicyTypeResource policyTypeResource) {
+ this.policyTypeResource = policyTypeResource;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/policytypes/appliesto.jsp", this);
+ }
+
+ public TPolicyType getPolicyType() {
+ return this.policyTypeResource.getPolicyType();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java
new file mode 100644
index 0000000..036cc73
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/LanguageResource.java
@@ -0,0 +1,28 @@
+package org.eclipse.winery.repository.resources.entitytypes.policytypes;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class LanguageResource {
+
+ private PolicyTypeResource policyTypeResource;
+
+
+ public LanguageResource(PolicyTypeResource policyTypeResource) {
+ this.policyTypeResource = policyTypeResource;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/policytypes/language.jsp", this);
+ }
+
+ public String getLanguage() {
+ return this.policyTypeResource.getPolicyType().getPolicyLanguage();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java
new file mode 100644
index 0000000..62c728a
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypeResource.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.policytypes;
+
+import java.util.SortedSet;
+
+import javax.ws.rs.Path;
+
+import org.eclipse.winery.common.ids.definitions.PolicyTemplateId;
+import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TPolicyType;
+import org.eclipse.winery.repository.datatypes.select2.Select2OptGroup;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class PolicyTypeResource extends EntityTypeResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(PolicyTypeResource.class);
+
+
+ /**
+ * Constructor has to be public because of test cases
+ */
+ public PolicyTypeResource(PolicyTypeId id) {
+ super(id);
+ }
+
+ /**
+ * Convenience method to avoid casting at the caller's side.
+ */
+ public TPolicyType getPolicyType() {
+ return (TPolicyType) this.getElement();
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TPolicyType();
+ }
+
+ @Path("appliesto/")
+ public AppliesToResource getAppliesTo() {
+ return new AppliesToResource(this);
+ }
+
+ @Path("language/")
+ public LanguageResource getLanguage() {
+ return new LanguageResource(this);
+ }
+
+ @Override
+ public SortedSet<Select2OptGroup> getListOfAllInstances() {
+ return this.getListOfAllInstances(PolicyTemplateId.class);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java
new file mode 100644
index 0000000..17d4db0
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/policytypes/PolicyTypesResource.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.policytypes;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+/**
+ * Manages all policy types in all available namespaces <br />
+ * The actual implementation is done in the AbstractComponentsResource
+ */
+public class PolicyTypesResource extends AbstractComponentsResource<PolicyTypeResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java
new file mode 100644
index 0000000..a5338ed
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/JSPData.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.properties;
+
+import java.util.List;
+
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.tosca.TEntityType;
+
+/**
+ * Collects data used by the JSP
+ */
+public class JSPData {
+
+ // FIXME: this is a quick hack and provides a fixed list of available
+ // property types only. This list has to be made dynamically updatable (and offer plugins to edit)
+ // currently only http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#built-in-datatypes are supported
+ private static final String[] availablePropertyTypes = {"xsd:string", "xsd:boolean", "xsd:decimal", "xsd:float", "xsd:anyURI", "xsd:QName"};
+
+ private final PropertiesDefinitionResource propertiesDefinitionResource;
+ private final WinerysPropertiesDefinition wpd;
+
+
+ public JSPData(PropertiesDefinitionResource propertiesDefinitionResource, WinerysPropertiesDefinition wpd) {
+ this.propertiesDefinitionResource = propertiesDefinitionResource;
+ this.wpd = wpd;
+ }
+
+ public List<PropertyDefinitionKV> getPropertyDefinitionKVList() {
+ // as this method is used by the JSP, we have to initialize the list and not provide a fake list
+ // in other words: we are in the mode, where the user has chosen the winery property handling
+ assert (this.getIsWineryKeyValueProperties());
+ if (this.wpd.getPropertyDefinitionKVList() == null) {
+ return java.util.Collections.emptyList();
+ } else {
+ return this.wpd.getPropertyDefinitionKVList();
+ }
+ }
+
+ public Boolean getIsWineryKeyValueProperties() {
+ return (this.wpd != null);
+ // the jsp renders list data only if the list is existing
+ // we could (somehow) also always keep the old list, but we opted for keeping the choice between the four options also in the XML (and not storing stale data)
+ // in the case, the WPD is derived from XSD, the list is rendered nevertheless
+ }
+
+ public boolean getIsWineryKeyValuePropertiesDerivedFromXSD() {
+ return ((this.wpd != null) && (this.wpd.getIsDerivedFromXSD() != null));
+ }
+
+ public String[] getAvailablePropertyTypes() {
+ return JSPData.availablePropertyTypes;
+ }
+
+ public TEntityType getEntityType() {
+ return this.propertiesDefinitionResource.getEntityType();
+ }
+
+ public String getElementName() {
+ if (this.wpd == null) {
+ return null;
+ } else {
+ return this.wpd.getElementName();
+ }
+ }
+
+ public String getNamespace() {
+ if (this.wpd == null) {
+ return null;
+ } else {
+ return this.wpd.getNamespace();
+ }
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java
new file mode 100644
index 0000000..6a63791
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/PropertiesDefinitionResource.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.properties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.constants.MimeTypes;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.model.tosca.TEntityType.PropertiesDefinition;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.properties.winery.WinerysPropertiesDefinitionResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Models
+ * <ol>
+ * <li>TOSCA conforming properties definition (XML element / XML schema / none)</li>
+ * <li>Winery's KV properties (in the subresource "winery")</li>
+ * </ol>
+ *
+ * This class does not have "KV" in its name, because it models
+ * {@link TEntityType.PropertiesDefinition}
+ */
+public class PropertiesDefinitionResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(PropertiesDefinitionResource.class);
+
+ // We hold a copy of super.res as we work on the type EntityTypeResource instead of AbstractComponentInstanceResource
+ private final EntityTypeResource parentRes;
+
+ // we assume that this class is created at each request
+ // therefore, we can have "wpd" final
+ private final WinerysPropertiesDefinition wpd;
+
+
+ public PropertiesDefinitionResource(EntityTypeResource res) {
+ this.parentRes = res;
+ this.wpd = ModelUtilities.getWinerysPropertiesDefinition(res.getEntityType());
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/properties/propertiesDefinition.jsp", new JSPData(this, this.wpd));
+ }
+
+ public TEntityType getEntityType() {
+ return this.parentRes.getEntityType();
+ }
+
+ @Path("winery/")
+ public WinerysPropertiesDefinitionResource getWinerysPropertiesDefinitionResource() {
+ // this.wpd is null if there is no winery definition exisitin. The subresource handles that case, too
+ return new WinerysPropertiesDefinitionResource(this.parentRes, this.wpd);
+ }
+
+ @DELETE
+ public Response clearPropertiesDefinition() {
+ this.getEntityType().setPropertiesDefinition(null);
+ ModelUtilities.removeWinerysPropertiesDefinition(this.getEntityType());
+ return BackendUtils.persist(this.parentRes);
+ }
+
+ public boolean getIsWineryKeyValueProperties() {
+ return (this.wpd != null);
+ }
+
+ @GET
+ @Produces(MimeTypes.MIMETYPE_XSD)
+ public Response getXSD() {
+ if (this.getIsWineryKeyValueProperties()) {
+ return Response.ok().entity(ModelUtilities.getWinerysPropertiesDefinitionXSDAsDocument(this.wpd)).build();
+ } else {
+ // not yet implemented
+ // We would have to check the imports in the repo for the defined property
+ // This also has to be similarly done at the export to determine the right imports
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ }
+
+ @GET
+ @RestDoc(methodDescription = "We provide the XSD at . and at ./xsd/ to enable simple quering in the browser without the hazzle of setting the correct mime type.")
+ @Path("xsd/")
+ @Produces(MimeTypes.MIMETYPE_XSD)
+ public Response getXSDAtSubResource() {
+ return this.getXSD();
+ }
+
+ // @formatter:off
+ @POST
+ @RestDoc(methodDescription="Updates/creates a property based on XSD element or XML schema.")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response onPost(
+ @FormParam("name") @RestDocParam(description="Either xsdelement or xsdtype. 'name' comes from x-editable, which uses that as field name") String name,
+ @FormParam("value") @RestDocParam(description="The qname") String value) {
+ // @formatter:on
+ if (StringUtils.isEmpty(name)) {
+ return Response.status(Status.BAD_REQUEST).entity("You have to provide a key/type or a name/value pair").build();
+ }
+ if (StringUtils.isEmpty(value)) {
+ return Response.status(Status.BAD_REQUEST).entity("If a name is provided, a value has also to be provided").build();
+ }
+
+ // first of all, remove Winery's Properties definition (if it exists)
+ ModelUtilities.removeWinerysPropertiesDefinition(this.getEntityType());
+
+ QName qname = QName.valueOf(value);
+
+ // replace old properties definition by new one
+ PropertiesDefinition def = new PropertiesDefinition();
+ if (name.equals("xsdtype")) {
+ def.setType(qname);
+ } else if (name.equals("xsdelement")) {
+ def.setElement(qname);
+ } else {
+ return Response.status(Status.BAD_REQUEST).entity("Invalid name. Choose xsdelement or xsdtype").build();
+ }
+ this.getEntityType().setPropertiesDefinition(def);
+ List<String> errors = new ArrayList<>();
+ BackendUtils.deriveWPD(this.getEntityType(), errors);
+ // currently the errors are just logged
+ for (String error : errors) {
+ PropertiesDefinitionResource.logger.debug(error);
+ }
+ return BackendUtils.persist(this.parentRes);
+
+ }
+
+} \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java
new file mode 100644
index 0000000..f967042
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVListResource.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.properties.winery;
+
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV;
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * Supports Winery's k/v properties introducing sub resources
+ * "PropertyDefinition", which defines <em>one</em> property
+ */
+public class PropertyDefinitionKVListResource extends EntityWithIdCollectionResource<PropertyDefinitionKVResource, PropertyDefinitionKV> {
+
+ public PropertyDefinitionKVListResource(EntityTypeResource res, PropertyDefinitionKVList list) {
+ super(PropertyDefinitionKVResource.class, PropertyDefinitionKV.class, list, res);
+ }
+
+ @Override
+ public String getId(PropertyDefinitionKV entity) {
+ return entity.getKey();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java
new file mode 100644
index 0000000..00a8d24
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/PropertyDefinitionKVResource.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.properties.winery;
+
+import java.util.List;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKV;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+import org.restdoc.annotations.RestDoc;
+
+/**
+ * Models a definition of one property
+ *
+ * This is NOT in line with CSPRD01, which forces one element of one type
+ */
+public class PropertyDefinitionKVResource extends EntityWithIdResource<PropertyDefinitionKV> {
+
+ public PropertyDefinitionKVResource(IIdDetermination<PropertyDefinitionKV> idDetermination, PropertyDefinitionKV o, int idx, List<PropertyDefinitionKV> list, AbstractComponentInstanceResource res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ public PropertyDefinitionKVResource(IIdDetermination<PropertyDefinitionKV> idDetermination, PropertyDefinitionKV o, int idx, List<PropertyDefinitionKV> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ @GET
+ @RestDoc(methodDescription = "@return type is the 'id' of the type ('shortType'), not the full type name")
+ @Path("type")
+ public String getType() {
+ return this.o.getType();
+ }
+
+ @PUT
+ @RestDoc(methodDescription = "@return type is the 'id' of the type ('shortType'), not the full type name")
+ @Path("type")
+ public Response setType(@FormParam("type") String type) {
+ this.o.setType(type);
+ return BackendUtils.persist(this.res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java
new file mode 100644
index 0000000..0d219e3
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/properties/winery/WinerysPropertiesDefinitionResource.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.properties.winery;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TEntityType;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.propertydefinitionkv.PropertyDefinitionKVList;
+import org.eclipse.winery.common.propertydefinitionkv.WinerysPropertiesDefinition;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+import org.restdoc.annotations.RestDoc;
+
+import com.sun.jersey.api.NotFoundException;
+
+public class WinerysPropertiesDefinitionResource {
+
+ private final EntityTypeResource res;
+ private final WinerysPropertiesDefinition wpd;
+
+
+ /**
+ * @param res the resource where winery's k/v properties are defined
+ * @param wpd winery's properties definition object, MAY be null
+ */
+ public WinerysPropertiesDefinitionResource(EntityTypeResource res, WinerysPropertiesDefinition wpd) {
+ this.res = res;
+ this.wpd = wpd;
+ }
+
+ @POST
+ @RestDoc(methodDescription = "switches the mode to winery properties instead of element/type properties")
+ public Response onPost() {
+ TEntityType et = this.res.getEntityType();
+
+ // clear current properties definition
+ et.setPropertiesDefinition(null);
+
+ // create empty winery properties definition and persist it
+ WinerysPropertiesDefinition wpd = new WinerysPropertiesDefinition();
+ ModelUtilities.replaceWinerysPropertiesDefinition(et, wpd);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("namespace")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getNamespace() {
+ if (this.wpd == null) {
+ throw new NotFoundException();
+ }
+ return this.wpd.getNamespace();
+ }
+
+ @Path("namespace")
+ @PUT
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response setNamespace(String namespace) {
+ if (this.wpd == null) {
+ throw new NotFoundException();
+ }
+ this.wpd.setNamespace(namespace);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("elementname")
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String getElementName() {
+ if (this.wpd == null) {
+ throw new NotFoundException();
+ }
+ return this.wpd.getElementName();
+ }
+
+ @Path("elementname")
+ @PUT
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response setLocalname(String elementName) {
+ if (this.wpd == null) {
+ throw new NotFoundException();
+ }
+ this.wpd.setElementName(elementName);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("elementname")
+ @PUT
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response setLocalnameViaWebUI(@FormParam(value = "name") String elementName) {
+ if (this.wpd == null) {
+ throw new NotFoundException();
+ }
+ this.wpd.setElementName(elementName);
+ return BackendUtils.persist(this.res);
+ }
+
+ /**
+ * Here, also the addition of k/v properties is handled.
+ */
+ @Path("list/")
+ public PropertyDefinitionKVListResource getListResource() {
+ if (this.wpd == null) {
+ throw new NotFoundException();
+ }
+ PropertyDefinitionKVList list = this.wpd.getPropertyDefinitionKVList();
+ if (list == null) {
+ list = new PropertyDefinitionKVList();
+ this.wpd.setPropertyDefinitionKVList(list);
+ }
+ return new PropertyDefinitionKVListResource(this.res, list);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java
new file mode 100644
index 0000000..c7cf2d6
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/ImplementationsOfOneRelationshipTypeResource.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeImplementationId;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.entitytypes.ImplementationsOfOneType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+public class ImplementationsOfOneRelationshipTypeResource extends ImplementationsOfOneType {
+
+ public ImplementationsOfOneRelationshipTypeResource(RelationshipTypeId typeId) {
+ super(typeId);
+ }
+
+
+ private static final Logger logger = LoggerFactory.getLogger(ImplementationsOfOneRelationshipTypeResource.class);
+
+
+ /**
+ * required by implementations.jsp
+ *
+ * Method similar top the one of ImplementationsOfOneNodeTypeResource
+ *
+ * @return for each node type implementation implementing the associated
+ * node type
+ */
+ @Override
+ public String getImplementationsTableData() {
+ String res;
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter tableDataSW = new StringWriter();
+ try {
+ JsonGenerator jGenerator = jsonFactory.createGenerator(tableDataSW);
+ jGenerator.writeStartArray();
+
+ Collection<RelationshipTypeImplementationId> allNTIids = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, this.getTypeId().getQName());
+ for (RelationshipTypeImplementationId ntiID : allNTIids) {
+ jGenerator.writeStartArray();
+ jGenerator.writeString(ntiID.getNamespace().getDecoded());
+ jGenerator.writeString(ntiID.getXmlId().getDecoded());
+ jGenerator.writeEndArray();
+ }
+ jGenerator.writeEndArray();
+ jGenerator.close();
+ tableDataSW.close();
+ res = tableDataSW.toString();
+ } catch (Exception e) {
+ ImplementationsOfOneRelationshipTypeResource.logger.error(e.getMessage(), e);
+ res = "[]";
+ }
+ return res;
+ }
+
+ @Override
+ public String getType() {
+ return "relationshiptype";
+ }
+
+ @Override
+ public String getTypeStr() {
+ return "Relationship Type";
+ }
+
+ @Override
+ public Response getJSON() {
+ Collection<RelationshipTypeImplementationId> allImplementations = BackendUtils.getAllElementsRelatedWithATypeAttribute(RelationshipTypeImplementationId.class, this.getTypeId().getQName());
+ ArrayList<QName> res = new ArrayList<QName>(allImplementations.size());
+ for (RelationshipTypeImplementationId id : allImplementations) {
+ res.add(id.getQName());
+ }
+ return Response.ok().entity(res).build();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java
new file mode 100644
index 0000000..c874bd5
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypeResource.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes;
+
+import java.util.Collection;
+import java.util.SortedSet;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TRelationshipType;
+import org.eclipse.winery.model.tosca.TRelationshipType.SourceInterfaces;
+import org.eclipse.winery.model.tosca.TRelationshipType.TargetInterfaces;
+import org.eclipse.winery.model.tosca.TRelationshipType.ValidSource;
+import org.eclipse.winery.model.tosca.TRelationshipType.ValidTarget;
+import org.eclipse.winery.model.tosca.TTopologyElementInstanceStates;
+import org.eclipse.winery.common.ids.definitions.NodeTypeId;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.entitytypes.InstanceStatesResource;
+import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource;
+import org.eclipse.winery.repository.resources.interfaces.InterfacesResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class RelationshipTypeResource extends TopologyGraphElementEntityTypeResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(RelationshipTypeResource.class);
+
+
+ public RelationshipTypeResource(RelationshipTypeId id) {
+ super(id);
+ }
+
+ @Path("implementations/")
+ public ImplementationsOfOneRelationshipTypeResource getImplementations() {
+ return new ImplementationsOfOneRelationshipTypeResource((RelationshipTypeId) this.id);
+ }
+
+ @Path("visualappearance/")
+ public VisualAppearanceResource getVisualAppearanceResource() {
+ return new VisualAppearanceResource(this, this.getElement().getOtherAttributes(), (RelationshipTypeId) this.id);
+ }
+
+ @Path("instancestates/")
+ public InstanceStatesResource getInstanceStatesResource() {
+ TTopologyElementInstanceStates instanceStates = this.getRelationshipType().getInstanceStates();
+ if (instanceStates == null) {
+ // if an explicit (empty) list does not exist, create it
+ instanceStates = new TTopologyElementInstanceStates();
+ this.getRelationshipType().setInstanceStates(instanceStates);
+ }
+ return new InstanceStatesResource(this.getRelationshipType().getInstanceStates(), this);
+ }
+
+ @Path("sourceinterfaces/")
+ public InterfacesResource getSourceInterfaces() {
+ SourceInterfaces interfaces = this.getRelationshipType().getSourceInterfaces();
+ if (interfaces == null) {
+ interfaces = new SourceInterfaces();
+ this.getRelationshipType().setSourceInterfaces(interfaces);
+ }
+ return new InterfacesResource("source", interfaces.getInterface(), this);
+ }
+
+ @Path("targetinterfaces/")
+ public InterfacesResource getTargetInterfaces() {
+ TargetInterfaces interfaces = this.getRelationshipType().getTargetInterfaces();
+ if (interfaces == null) {
+ interfaces = new TargetInterfaces();
+ this.getRelationshipType().setTargetInterfaces(interfaces);
+ }
+ return new InterfacesResource("target", interfaces.getInterface(), this);
+ }
+
+ @Path("validendings/")
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML() {
+ Viewable viewable = new Viewable("/jsp/entitytypes/relationshiptypes/validendings.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+
+ @Path("validsource")
+ @GET
+ public String getValidSource() {
+ ValidSource validSource;
+ if (((validSource = this.getRelationshipType().getValidSource()) == null) || (validSource.getTypeRef() == null)) {
+ return null;
+ }
+ return this.getRelationshipType().getValidSource().getTypeRef().toString();
+ }
+
+ @Path("validsource")
+ @PUT
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response setValidSource(String typeRef) {
+ ValidSource vs = new ValidSource();
+ QName qname = QName.valueOf(typeRef);
+ vs.setTypeRef(qname);
+ this.getRelationshipType().setValidSource(vs);
+ return BackendUtils.persist(this);
+ }
+
+ @Path("validtarget")
+ @GET
+ public String getValidTarget() {
+ ValidTarget validTarget;
+ if (((validTarget = this.getRelationshipType().getValidTarget()) == null) || (validTarget.getTypeRef() == null)) {
+ return null;
+ }
+ return this.getRelationshipType().getValidTarget().getTypeRef().toString();
+ }
+
+ @Path("validtarget")
+ @PUT
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response setValidTarget(String typeRef) {
+ ValidTarget vt = new ValidTarget();
+ QName qname = QName.valueOf(typeRef);
+ vt.setTypeRef(qname);
+ this.getRelationshipType().setValidTarget(vt);
+ return BackendUtils.persist(this);
+ }
+
+ /**
+ * Required for validendings.jsp
+ */
+ public Collection<NodeTypeId> getPossibleValidEndings() {
+ SortedSet<NodeTypeId> allNodeTypeIds = Repository.INSTANCE.getAllTOSCAComponentIds(NodeTypeId.class);
+ return allNodeTypeIds;
+ }
+
+ /**
+ * Convenience method to avoid casting at the caller's side.
+ */
+ public TRelationshipType getRelationshipType() {
+ return (TRelationshipType) this.getElement();
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TRelationshipType();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java
new file mode 100644
index 0000000..1c73ab0
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/RelationshipTypesResource.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+public class RelationshipTypesResource extends AbstractComponentsResource<RelationshipTypeResource> {
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java
new file mode 100644
index 0000000..c17c19b
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/relationshiptypes/VisualAppearanceResource.java
@@ -0,0 +1,291 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ * Jerome Tagliaferri - support for setting the color
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.relationshiptypes;
+
+import java.io.StringWriter;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.constants.Defaults;
+import org.eclipse.winery.common.constants.Namespaces;
+import org.eclipse.winery.common.constants.QNames;
+import org.eclipse.winery.common.ids.definitions.RelationshipTypeId;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.datatypes.ids.elements.VisualAppearanceId;
+import org.eclipse.winery.repository.resources.GenericVisualAppearanceResource;
+import org.restdoc.annotations.RestDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.sun.jersey.api.view.Viewable;
+
+public class VisualAppearanceResource extends GenericVisualAppearanceResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(VisualAppearanceResource.class);
+
+ private static final QName QNAME_ARROWHEAD_SOURCE = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "sourceArrowHead");
+ private static final QName QNAME_ARROWHEAD_TARGET = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "targetArrowHead");
+ private static final QName QNAME_DASH = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "dash");
+ private static final QName QNAME_LINEWIDTH = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "linewidth");
+ private static final QName QNAME_HOVER_COLOR = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "hovercolor");
+
+
+ public VisualAppearanceResource(RelationshipTypeResource res, Map<QName, String> map, RelationshipTypeId parentId) {
+ super(res, map, new VisualAppearanceId(parentId));
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML() {
+ Viewable viewable = new Viewable("/jsp/entitytypes/relationshiptypes/visualappearance.jsp", this);
+ return Response.ok().entity(viewable).build();
+ }
+
+ @GET
+ @RestDoc(methodDescription = "@return JSON object to be used at jsPlumb.registerConnectionType('NAME', <data>)")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response getConnectionTypeForJsPlumbData() {
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter sw = new StringWriter();
+ try {
+ JsonGenerator jg = jsonFactory.createGenerator(sw);
+ jg.writeStartObject();
+
+ jg.writeFieldName("connector");
+ jg.writeString("Flowchart");
+
+ jg.writeFieldName("paintStyle");
+ jg.writeStartObject();
+ jg.writeFieldName("lineWidth");
+ jg.writeNumber(this.getLineWidth());
+ jg.writeFieldName("strokeStyle");
+ jg.writeObject(this.getColor());
+ String dash = this.getDash();
+ if (!StringUtils.isEmpty(dash)) {
+ String dashStyle = null;
+ switch (dash) {
+ case "dotted":
+ dashStyle = "1 5";
+ break;
+ case "dotted2":
+ dashStyle = "3 4";
+ break;
+ case "plain":
+ // default works
+ // otherwise, "1 0" can be used
+ break;
+ }
+ if (dashStyle != null) {
+ jg.writeStringField("dashstyle", dashStyle);
+ }
+ }
+ jg.writeEndObject();
+
+ jg.writeFieldName("hoverPaintStyle");
+ jg.writeStartObject();
+ jg.writeFieldName("strokeStyle");
+ jg.writeObject(this.getHoverColor());
+ jg.writeEndObject();
+
+ // BEGIN: Overlays
+
+ jg.writeFieldName("overlays");
+ jg.writeStartArray();
+
+ // source arrow head
+ String head = this.getSourceArrowHead();
+ if (!head.equals("none")) {
+ jg.writeStartArray();
+ jg.writeString(head);
+
+ jg.writeStartObject();
+
+ jg.writeFieldName("location");
+ jg.writeNumber(0);
+
+ // arrow should point towards the node and not away from it
+ jg.writeFieldName("direction");
+ jg.writeNumber(-1);
+
+ jg.writeFieldName("width");
+ jg.writeNumber(20);
+
+ jg.writeFieldName("length");
+ jg.writeNumber(12);
+
+ jg.writeEndObject();
+ jg.writeEndArray();
+ }
+
+ // target arrow head
+ head = this.getTargetArrowHead();
+ if (!head.equals("none")) {
+ jg.writeStartArray();
+ jg.writeString(head);
+ jg.writeStartObject();
+ jg.writeFieldName("location");
+ jg.writeNumber(1);
+ jg.writeFieldName("width");
+ jg.writeNumber(20);
+ jg.writeFieldName("length");
+ jg.writeNumber(12);
+ jg.writeEndObject();
+ jg.writeEndArray();
+ }
+
+ // Type in brackets on the arrow
+ jg.writeStartArray();
+ jg.writeString("Label");
+ jg.writeStartObject();
+ jg.writeStringField("id", "label");
+ jg.writeStringField("label", "(" + ((RelationshipTypeResource) this.res).getName() + ")");
+ jg.writeStringField("cssClass", "relationshipTypeLabel");
+ jg.writeFieldName("location");
+ jg.writeNumber(0.5);
+ jg.writeEndObject();
+ jg.writeEndArray();
+
+ jg.writeEndArray();
+
+ // END: Overlays
+
+ jg.writeEndObject();
+
+ jg.close();
+ } catch (Exception e) {
+ VisualAppearanceResource.logger.error(e.getMessage(), e);
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build();
+ }
+ String res = sw.toString();
+ return Response.ok(res).build();
+ }
+
+ private String getOtherAttributeWithDefault(QName qname, String def) {
+ String res = this.otherAttributes.get(qname);
+ if (StringUtils.isEmpty(res)) {
+ return def;
+ } else {
+ return res;
+ }
+ }
+
+ /* * * source arrow head * * */
+
+ public String getSourceArrowHead() {
+ return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_ARROWHEAD_SOURCE, Defaults.DEFAULT_RT_ARROWHEAD_SOURCE);
+ }
+
+ @PUT
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Path("sourcearrowhead")
+ public Response onPutSourceHead(String config) {
+ if (StringUtils.isEmpty(config)) {
+ return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build();
+ }
+ this.otherAttributes.put(VisualAppearanceResource.QNAME_ARROWHEAD_SOURCE, config);
+ return BackendUtils.persist(this.res);
+ }
+
+ /* * * target arrow head * * */
+
+ public String getTargetArrowHead() {
+ return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_ARROWHEAD_TARGET, Defaults.DEFAULT_RT_ARROWHEAD_TARGET);
+ }
+
+ @PUT
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Path("targetarrowhead")
+ public Response onPutTargetHead(String config) {
+ if (StringUtils.isEmpty(config)) {
+ return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build();
+ }
+ this.otherAttributes.put(VisualAppearanceResource.QNAME_ARROWHEAD_TARGET, config);
+ return BackendUtils.persist(this.res);
+ }
+
+ /* * *
+ *
+ * stroke dash array / represents the line
+ *
+ * Attention: if a linewidth != 1 is chosen, the dash has to be multiplied somehow by the line width
+ * See: http://jsplumbtoolkit.com/doc/paint-styles:
+ * "The dashstyle attribute is specified as an array of strokes and spaces, where each value is some multiple of the width of the Connector"
+ *
+ * * * */
+
+ public String getDash() {
+ return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_DASH, Defaults.DEFAULT_RT_DASH);
+ }
+
+ @PUT
+ @Consumes(MediaType.TEXT_PLAIN)
+ @Path("dash")
+ public Response onPutDash(String config) {
+ if (StringUtils.isEmpty(config)) {
+ return Response.status(Status.BAD_REQUEST).entity("config must not be empty").build();
+ }
+ this.otherAttributes.put(VisualAppearanceResource.QNAME_DASH, config);
+ return BackendUtils.persist(this.res);
+ }
+
+ /* * * stroke/line width * * */
+
+ public String getLineWidth() {
+ return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_LINEWIDTH, Defaults.DEFAULT_RT_LINEWIDTH);
+ }
+
+ /* * * color * * */
+
+ /**
+ * read by topologytemplateeditor.jsp via ${it.color}
+ */
+ public String getColor() {
+ return BackendUtils.getColorAndSetDefaultIfNotExisting(this.getId().getParent().getXmlId().getDecoded(), QNames.QNAME_COLOR, this.otherAttributes, this.res);
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Path("color")
+ public Response onPutColor(@FormParam("color") String color) {
+ this.otherAttributes.put(QNames.QNAME_COLOR, color);
+ return BackendUtils.persist(this.res);
+ }
+
+ /**
+ * read by topologytemplateeditor.jsp via ${it.hoverColor}
+ */
+ public String getHoverColor() {
+ return this.getOtherAttributeWithDefault(VisualAppearanceResource.QNAME_HOVER_COLOR, Defaults.DEFAULT_RT_HOVER_COLOR);
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Path("hovercolor")
+ public Response onPutHoverColor(@FormParam("color") String color) {
+ this.otherAttributes.put(VisualAppearanceResource.QNAME_HOVER_COLOR, color);
+ return BackendUtils.persist(this.res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java
new file mode 100644
index 0000000..c076835
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequiredCapabilityTypeResource.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.requirementtypes;
+
+import java.util.Collection;
+import java.util.SortedSet;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ids.definitions.CapabilityTypeId;
+import org.eclipse.winery.model.tosca.TRequirementType;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+
+import com.sun.jersey.api.NotFoundException;
+import com.sun.jersey.api.view.Viewable;
+
+public class RequiredCapabilityTypeResource {
+
+ private RequirementTypeResource requirementTypeResource;
+
+
+ public RequiredCapabilityTypeResource(RequirementTypeResource requirementTypeResource) {
+ this.requirementTypeResource = requirementTypeResource;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/entitytypes/requirementtypes/requiredcapabilitytype.jsp", this);
+ }
+
+ public TRequirementType getRequirementType() {
+ return this.requirementTypeResource.getRequirementType();
+ }
+
+ @PUT
+ @Consumes(MediaType.TEXT_PLAIN)
+ public Response putRequiredCapabilityType(String type) {
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).entity("type must not be empty").build();
+ }
+ QName qname = QName.valueOf(type);
+ CapabilityTypeId id = new CapabilityTypeId(qname);
+ if (Repository.INSTANCE.exists(id)) {
+ // everything allright. Store new reference
+ this.getRequirementType().setRequiredCapabilityType(qname);
+ return BackendUtils.persist(this.requirementTypeResource);
+ } else {
+ throw new NotFoundException("Given QName could not be resolved to an existing capability type");
+ }
+ }
+
+ @DELETE
+ public Response deleteRequiredCapabilityType() {
+ this.getRequirementType().setRequiredCapabilityType(null);
+ return BackendUtils.persist(this.requirementTypeResource);
+ }
+
+ /** required for jsp **/
+ public Collection<QName> getAllCapabilityTypes() {
+ SortedSet<CapabilityTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(CapabilityTypeId.class);
+ return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java
new file mode 100644
index 0000000..0f143fb
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypeResource.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.requirementtypes;
+
+import javax.ws.rs.Path;
+
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TRequirementType;
+import org.eclipse.winery.common.ids.definitions.RequirementTypeId;
+import org.eclipse.winery.repository.resources.EntityTypeResource;
+
+public class RequirementTypeResource extends EntityTypeResource {
+
+ public RequirementTypeResource(RequirementTypeId id) {
+ super(id);
+ }
+
+ /**
+ * Convenience method to avoid casting at the caller's side.
+ */
+ public TRequirementType getRequirementType() {
+ return (TRequirementType) this.getElement();
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TRequirementType();
+ }
+
+ @Path("requiredcapabilitytype/")
+ public RequiredCapabilityTypeResource getRequiredCapabilityTypeResource() {
+ return new RequiredCapabilityTypeResource(this);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java
new file mode 100644
index 0000000..955e4fb
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/entitytypes/requirementtypes/RequirementTypesResource.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.entitytypes.requirementtypes;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+/**
+ * Manages all capability types in all available namespaces <br />
+ * The actual implementation is done in the AbstractComponentsResource
+ */
+public class RequirementTypesResource extends AbstractComponentsResource<RequirementTypeResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java
new file mode 100644
index 0000000..82ff02e
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/ImportsResource.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.imports;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportsResource;
+import org.eclipse.winery.repository.resources.imports.xsdimports.XSDImportsResource;
+
+/**
+ * The specification does not nest the sequence of import elements in an imports
+ * container. We introduce such a container to be consistent with the other
+ * resource naming
+ */
+public class ImportsResource {
+
+ @Path("{id}/")
+ public AbstractComponentsResource getXSDsResource(@PathParam("id") String id) {
+ // once: decoding for browser locations
+ id = Util.URLdecode(id);
+ // once again: real URI
+ id = Util.URLdecode(id);
+ if (id.equals("http://www.w3.org/2001/XMLSchema")) {
+ // Models http://www.w3.org/2001/XMLSchema. We do not use xsd instead of the
+ // encoded namespace, because this induces special cases at many places
+ return new XSDImportsResource();
+ } else {
+ return new GenericImportsResource(id);
+ }
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java
new file mode 100644
index 0000000..ddcb462
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportResource.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.imports.genericimports;
+
+import java.util.SortedSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImport;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceResource;
+
+public class GenericImportResource extends AbstractComponentInstanceResource {
+
+ // The import belonging to this resource
+ protected final TImport theImport;
+
+
+ public GenericImportResource(GenericImportId id) {
+ super(id);
+
+ boolean needsPersistence = false;
+
+ if (this.getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation().isEmpty()) {
+ // super class loaded an existing definitions
+
+ // we have to manually assign our import right
+ this.theImport = this.getDefinitions().getImport().get(0);
+
+ // element is not assigned as there are no service templates/...
+ // we assign the value to be sure that no NPEs occur
+ this.element = this.theImport;
+ } else {
+ // super class created a new import
+
+ // store it locally
+ this.theImport = (TImport) this.element;
+
+ // undo the side effect of adding it at the wrong place at TDefinitions
+ this.getDefinitions().getServiceTemplateOrNodeTypeOrNodeTypeImplementation().clear();
+
+ // add import at the right place
+ this.getDefinitions().getImport().add(this.theImport);
+
+ // Super class has persisted the definitions
+ // We have to persist the new variant
+ needsPersistence = true;
+ }
+
+ if (this.theImport.getLocation() == null) {
+ // invalid import -- try to synchronize with storage
+
+ SortedSet<RepositoryFileReference> containedFiles = Repository.INSTANCE.getContainedFiles(id);
+ // there is also a .definitions contained
+ // we are only interested in the non-.definitions
+ for (RepositoryFileReference ref : containedFiles) {
+ if (!ref.getFileName().endsWith(".definitions")) {
+ // associated file found
+ // set the filename of the import to the found xsd
+ // TODO: no more validity checks are done currently. In the case of XSD: targetNamespace matches, not more than one xsd
+ this.theImport.setLocation(ref.getFileName());
+ needsPersistence = true;
+ break;
+ }
+ }
+ }
+
+ if (needsPersistence) {
+ BackendUtils.persist(this);
+ }
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ throw new IllegalStateException("This should not never happen.");
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ // this.theImport cannot be used as this method is called by the super constructor
+ ((TImport) this.element).setNamespace(this.id.getNamespace().getDecoded());
+ }
+
+ @GET
+ @Path("{filename}")
+ public Response getFile(@PathParam("filename") String fileName) {
+ fileName = Util.URLdecode(fileName);
+ String location;
+ if ((location = this.getLocation()) == null) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ if (!location.equals(fileName)) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ RepositoryFileReference ref = new RepositoryFileReference(this.id, location);
+ return BackendUtils.returnRepoPath(ref, null);
+
+ }
+
+ public String getLocation() {
+ return this.theImport.getLocation();
+ }
+
+ /**
+ * @return a name suitable for componentnaming.jspf
+ */
+ public String getName() {
+ if (this.getLocation() == null) {
+ return this.id.getXmlId().getDecoded();
+ } else {
+ return this.getLocation();
+ }
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java
new file mode 100644
index 0000000..9117175
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/genericimports/GenericImportsResource.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.imports.genericimports;
+
+import org.eclipse.winery.common.ids.definitions.imports.GenericImportId;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+/**
+ * Manages a certain kind of imports without special treatments
+ */
+public class GenericImportsResource extends AbstractComponentsResource<GenericImportResource> {
+
+ private String type;
+
+
+ /**
+ * @param id the (decoded) id, e.g., http://schemas.xmlsoap.org/wsdl/
+ */
+ public GenericImportsResource(String id) {
+ this.type = id;
+ }
+
+ @Override
+ public GenericImportResource getComponentInstaceResource(String namespace, String id, boolean encoded) {
+ GenericImportId iId = new GenericImportId(namespace, id, encoded, this.type);
+ return new GenericImportResource(iId);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java
new file mode 100644
index 0000000..49ea468
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportResource.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.imports.xsdimports;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.XMLConstants;
+
+import org.apache.xerces.xs.XSConstants;
+import org.apache.xerces.xs.XSModel;
+import org.apache.xerces.xs.XSNamedMap;
+import org.apache.xerces.xs.XSObject;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.definitions.imports.XSDImportId;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TImport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.imports.genericimports.GenericImportResource;
+import org.restdoc.annotations.RestDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+/**
+ * Even if we are not a component instance, we use that infrastructure to manage
+ * imports. Some hacks will be necessary. However, these are less effort than
+ * doing a clean design
+ */
+public class XSDImportResource extends GenericImportResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(XSDImportResource.class);
+
+
+ public XSDImportResource(XSDImportId id) {
+ super(id);
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ TImport imp = new TImport();
+ imp.setImportType(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+ return imp;
+ }
+
+ /**
+ * public required by XSDImportsResource
+ *
+ * @return null if XSD file does not exist
+ */
+ public RepositoryFileReference getXSDFileReference() {
+ String loc = this.getLocation();
+ if (loc == null) {
+ return null;
+ }
+ final RepositoryFileReference ref = new RepositoryFileReference(this.id, loc);
+ return ref;
+ }
+
+ /**
+ * @return null if no file is associated
+ */
+ private XSModel getXSModel() {
+ final RepositoryFileReference ref = this.getXSDFileReference();
+ return BackendUtils.getXSModel(ref);
+ }
+
+ // we need "unchecked", because of the parsing of the cache
+ @SuppressWarnings("unchecked")
+ public Collection<String> getAllDefinedLocalNames(short type) {
+ RepositoryFileReference ref = this.getXSDFileReference();
+ if (ref == null) {
+ return Collections.emptySet();
+ }
+ Date lastUpdate = Repository.INSTANCE.getLastUpdate(ref);
+
+ String cacheFileName = "definedLocalNames " + Integer.toString(type) + ".cache";
+ RepositoryFileReference cacheRef = new RepositoryFileReference(this.id, cacheFileName);
+ boolean cacheNeedsUpdate = true;
+ if (Repository.INSTANCE.exists(cacheRef)) {
+ Date lastUpdateCache = Repository.INSTANCE.getLastUpdate(cacheRef);
+ if (lastUpdate.compareTo(lastUpdateCache) <= 0) {
+ cacheNeedsUpdate = false;
+ }
+ }
+
+ List<String> result;
+ if (cacheNeedsUpdate) {
+
+ XSModel model = this.getXSModel();
+ if (model == null) {
+ return Collections.emptySet();
+ }
+ XSNamedMap components = model.getComponents(type);
+ //@SuppressWarnings("unchecked")
+ int len = components.getLength();
+ result = new ArrayList<String>(len);
+ for (int i = 0; i < len; i++) {
+ XSObject item = components.item(i);
+ // if queried for TYPE_DEFINITION, then XSD base types (such as IDREF) are also returned
+ // We want to return only types defined in the namespace of this resource
+ if (item.getNamespace().equals(this.id.getNamespace().getDecoded())) {
+ result.add(item.getName());
+ }
+ }
+
+ String cacheContent = null;
+ try {
+ cacheContent = Utils.mapper.writeValueAsString(result);
+ } catch (JsonProcessingException e) {
+ XSDImportResource.logger.error("Could not generate cache content", e);
+ }
+ try {
+ Repository.INSTANCE.putContentToFile(cacheRef, cacheContent, MediaType.APPLICATION_JSON_TYPE);
+ } catch (IOException e) {
+ XSDImportResource.logger.error("Could not update cache", e);
+ }
+ } else {
+ // read content from cache
+ // cache should contain most recent information
+ try (InputStream is = Repository.INSTANCE.newInputStream(cacheRef)) {
+ result = Utils.mapper.readValue(is, java.util.List.class);
+ } catch (IOException e) {
+ XSDImportResource.logger.error("Could not read from cache", e);
+ result = Collections.emptyList();
+ }
+ }
+ return result;
+ }
+
+ public Collection<String> getAllDefinedElementsLocalNames() {
+ return this.getAllDefinedLocalNames(XSConstants.ELEMENT_DECLARATION);
+ }
+
+ public Collection<String> getAllDefinedTypesLocalNames() {
+ return this.getAllDefinedLocalNames(XSConstants.TYPE_DEFINITION);
+ }
+
+ @GET
+ @RestDoc(methodDescription = "May be used by the modeler to generate an XML editor based on the XML schema")
+ // we cannot use "MimeTypes.MIMETYPE_XSD" here as the latter is "text/xml" and org.eclipse.winery.repository.resources.AbstractComponentInstanceResource.getDefinitionsAsResponse() also produces text/xml
+ @Produces("text/xsd")
+ public Response getXSD() {
+ String location;
+ if ((location = this.getLocation()) == null) {
+ return Response.status(Status.NOT_FOUND).build();
+ }
+ RepositoryFileReference ref = new RepositoryFileReference(this.id, location);
+ return BackendUtils.returnRepoPath(ref, null);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java
new file mode 100644
index 0000000..61af3bd
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/imports/xsdimports/XSDImportsResource.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.imports.xsdimports;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.common.ids.definitions.imports.XSDImportId;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+import org.restdoc.annotations.RestDoc;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+/**
+ * Manages all imports of type XML Schema Definition <br />
+ * The actual implementation is done in the AbstractComponentsResource
+ *
+ * FIXME: This class should be generalized to handle ImportId
+ */
+public class XSDImportsResource extends AbstractComponentsResource<XSDImportResource> {
+
+ @Path("{namespace}/")
+ @GET
+ @RestDoc(methodDescription = "Returns all available local names of defined elements in this namespace")
+ @Produces(MediaType.APPLICATION_JSON)
+ public String getAllElementLocalNames(@PathParam("namespace") String nsString, @QueryParam(value = "elements") String returnElements, @QueryParam(value = "types") String returnTypes) {
+ // returnElements is not read as either types or elements may be read
+ Set<String> allNCNames = this.getAllElementLocalNamesAsSet(nsString, returnTypes != null);
+ try {
+ return Utils.mapper.writeValueAsString(allNCNames);
+ } catch (JsonProcessingException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * @param nsString the namesapce as String
+ * @param returnTypes true: return ElementTypes, false: return Elements
+ */
+ private Set<String> getAllElementLocalNamesAsSet(final String nsString, final boolean getTypes) {
+ Set<XSDImportId> importsOfNS = this.getImportsOfNS(nsString);
+
+ // TreeSet enables ordering
+ Set<String> allNCNames = new TreeSet<String>();
+
+ for (XSDImportId imp : importsOfNS) {
+ XSDImportResource res = new XSDImportResource(imp);
+ Collection<String> col;
+ if (getTypes) {
+ col = res.getAllDefinedTypesLocalNames();
+ } else {
+ col = res.getAllDefinedElementsLocalNames();
+ }
+ allNCNames.addAll(col);
+ }
+ return allNCNames;
+ }
+
+ /**
+ * Finds out all imports belonging to the given namespace
+ *
+ * @param nsString the namespace to query
+ */
+ private Set<XSDImportId> getImportsOfNS(final String nsString) {
+ // FIXME: Currently not supported by the repository, therefore, we filter by hand
+ Set<XSDImportId> allImports = Repository.INSTANCE.getAllTOSCAComponentIds(XSDImportId.class);
+ Namespace ns = new Namespace(nsString, true);
+ Set<XSDImportId> importsOfNs = new HashSet<XSDImportId>();
+ for (XSDImportId imp : allImports) {
+ if (imp.getNamespace().equals(ns)) {
+ importsOfNs.add(imp);
+ }
+ }
+ return importsOfNs;
+ }
+
+ /**
+ * Returns a mapping from localnames to XSD files, containing the defined
+ * local names for the given namespace
+ */
+ public Map<String, RepositoryFileReference> getMapFromLocalNameToXSD(final String nsString, final boolean getTypes) {
+ Set<XSDImportId> importsOfNS = this.getImportsOfNS(nsString);
+ Map<String, RepositoryFileReference> result = new HashMap<>();
+ for (XSDImportId imp : importsOfNS) {
+ XSDImportResource res = new XSDImportResource(imp);
+ Collection<String> col;
+ if (getTypes) {
+ col = res.getAllDefinedTypesLocalNames();
+ } else {
+ col = res.getAllDefinedElementsLocalNames();
+ }
+ RepositoryFileReference ref = res.getXSDFileReference();
+ for (String localName : col) {
+ result.put(localName, ref);
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java
new file mode 100644
index 0000000..b7b7c15
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfaceResource.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.Path;
+
+import org.eclipse.winery.model.tosca.TInterface;
+import org.eclipse.winery.model.tosca.TOperation;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+
+public class InterfaceResource extends EntityWithIdResource<TInterface> {
+
+ private final TInterface iface;
+
+
+ public InterfaceResource(IIdDetermination<TInterface> idDetermination, TInterface o, int idx, List<TInterface> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ this.iface = o;
+ }
+
+ /**
+ * required by artifacts.jsp
+ */
+ public String getName() {
+ return this.iface.getName();
+ }
+
+ @Path("operations/")
+ public OperationsResource getOperationsResouce() {
+ List<TOperation> list = this.o.getOperation();
+ return new OperationsResource(list, this.res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java
new file mode 100644
index 0000000..4acfbd9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/InterfacesResource.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.model.tosca.TInterface;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.eclipse.winery.repository.resources.entitytypes.TopologyGraphElementEntityTypeResource;
+import org.eclipse.winery.repository.resources.entitytypes.relationshiptypes.RelationshipTypeResource;
+import org.restdoc.annotations.RestDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class InterfacesResource extends EntityWithIdCollectionResource<InterfaceResource, TInterface> {
+
+ private static final Logger logger = LoggerFactory.getLogger(InterfacesResource.class);
+
+ private TopologyGraphElementEntityTypeResource typeResource;
+
+ private String urlPrefix;
+
+
+ public InterfacesResource(IPersistable res, List<TInterface> list) {
+ super(InterfaceResource.class, TInterface.class, list, res);
+ }
+
+ /**
+ * @param urlPrefix prefix to be prepended to the URL.
+ * "source"|"target"|null. E.g., "source" for "sourceinterfaces"
+ */
+ public InterfacesResource(String urlPrefix, List<TInterface> list, IPersistable typeResource) {
+ super(InterfaceResource.class, TInterface.class, list, typeResource);
+ this.urlPrefix = urlPrefix;
+ this.typeResource = (TopologyGraphElementEntityTypeResource) typeResource;
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/interfaces/interfaces.jsp", this);
+ }
+
+ /**
+ * Implementation base: <br />
+ * {@link org.eclipse.winery.repository.resources.AbstractComponentResource.
+ * onPost(String)}
+ *
+ * @return entity: id of the stored interface
+ */
+ @POST
+ @RestDoc(methodDescription = "Creates a new interface. Returns conflict if interface already exists")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response onPost(@FormParam("interfaceName") String interfaceName) {
+ if (StringUtils.isEmpty(interfaceName)) {
+ return Response.status(Status.BAD_REQUEST).entity("null interfaceName").build();
+ }
+
+ TInterface iface = new TInterface();
+ iface.setName(interfaceName);
+
+ // check for duplicates
+ // return "conflict" if interface already exists
+ if (this.alreadyContains(iface)) {
+ return Response.status(Status.CONFLICT).build();
+ }
+
+ this.list.add(iface);
+ return BackendUtils.persist(this.res);
+ }
+
+ /**
+ * Required by interfaces.jsp
+ */
+ public String getUrlPrefix() {
+ return this.urlPrefix;
+ }
+
+ @Override
+ public String getId(TInterface entity) {
+ return entity.getName();
+ }
+
+ /**
+ * @return the namespace of the node/relationship type
+ */
+ public String getNamespace() {
+ return this.typeResource.getId().getNamespace().getDecoded();
+ }
+
+ /**
+ * @return the name of the node/relationship type
+ */
+ public String getName() {
+ return this.typeResource.getName();
+ }
+
+ public String getRelationshipTypeOrNodeTypeURLFragment() {
+ if (this.typeResource instanceof RelationshipTypeResource) {
+ return "relationshiptype";
+ } else {
+ return "nodetype";
+ }
+ }
+
+ public String getRelationshipTypeOrNodeType() {
+ if (this.typeResource instanceof RelationshipTypeResource) {
+ return "Relationship Type";
+ } else {
+ return "Node Type";
+ }
+ }
+
+ public String getTypeQName() {
+ String res = this.typeResource.getId().getQName().toString();
+ return res;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java
new file mode 100644
index 0000000..7657e99
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationResource.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.Path;
+
+import org.eclipse.winery.model.tosca.TInterface;
+import org.eclipse.winery.model.tosca.TOperation;
+import org.eclipse.winery.model.tosca.TOperation.InputParameters;
+import org.eclipse.winery.model.tosca.TOperation.OutputParameters;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OperationResource extends EntityWithIdResource<TOperation> {
+
+ private static final Logger logger = LoggerFactory.getLogger(OperationResource.class);
+
+
+ public OperationResource(IIdDetermination<TOperation> idDetermination, TOperation o, int idx, List<TOperation> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ /**
+ * @return TOperation object for the corresponding object of operationName
+ * in the operation list contained in the given interface. null if
+ * interface could not be found in list
+ */
+ public static TOperation getTOperation(String operationName, TInterface iface) {
+ List<TOperation> operationList = iface.getOperation();
+ for (TOperation op : operationList) {
+ if (op.getName().equals(operationName)) {
+ return op;
+ }
+ }
+ return null;
+ }
+
+ @Path("inputparameters/")
+ public ParametersResource getInputparameters() {
+ InputParameters inputParameters = this.o.getInputParameters();
+ if (inputParameters == null) {
+ inputParameters = new InputParameters();
+ this.o.setInputParameters(inputParameters);
+ }
+ return new ParametersResource(inputParameters.getInputParameter(), this.res);
+ }
+
+ @Path("outputparameters/")
+ public ParametersResource getOutputparameters() {
+ OutputParameters outputParameters = this.o.getOutputParameters();
+ if (outputParameters == null) {
+ outputParameters = new OutputParameters();
+ this.o.setOutputParameters(outputParameters);
+ }
+ return new ParametersResource(outputParameters.getOutputParameter(), this.res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java
new file mode 100644
index 0000000..3e214e4
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/OperationsResource.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.model.tosca.TOperation;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.restdoc.annotations.RestDocParam;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class OperationsResource extends EntityWithIdCollectionResource<OperationResource, TOperation> {
+
+ public OperationsResource(List<TOperation> list, IPersistable res) {
+ super(OperationResource.class, TOperation.class, list, res);
+ }
+
+ @Override
+ public String getId(TOperation entity) {
+ return entity.getName();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response createOperation(@FormParam("name") @RestDocParam(description = "used as name and id") String operationName) {
+ if (StringUtils.isEmpty(operationName)) {
+ return Response.status(Status.BAD_REQUEST).entity("operationName not provided").build();
+ }
+
+ operationName = Util.URLdecode(operationName);
+
+ // TODO: check for duplicates as in instance states
+
+ TOperation operation = new TOperation();
+ operation.setName(operationName);
+ this.list.add(operation);
+
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java
new file mode 100644
index 0000000..46662fd
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParameterResource.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013,2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TBoolean;
+import org.eclipse.winery.model.tosca.TParameter;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+
+public class ParameterResource extends EntityWithIdResource<TParameter> {
+
+ public ParameterResource(IIdDetermination<TParameter> idDetermination, TParameter o, int idx, List<TParameter> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ @GET
+ @Path("type")
+ public String getType() {
+ return this.o.getType();
+ }
+
+ @PUT
+ @Path("type")
+ public Response putType(@FormParam(value = "type") String type) {
+ this.o.setType(type);
+ return BackendUtils.persist(this.res);
+ }
+
+ @GET
+ @Path("required")
+ public String getRequired() {
+ return this.o.getRequired().toString();
+ }
+
+ @PUT
+ @Path("required")
+ public Response putRequired(@FormParam(value = "required") String required) {
+ TBoolean tb = TBoolean.valueOf(required);
+ this.o.setRequired(tb);
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java
new file mode 100644
index 0000000..c3afcbc
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/interfaces/ParametersResource.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.model.tosca.TBoolean;
+import org.eclipse.winery.model.tosca.TParameter;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class ParametersResource extends EntityWithIdCollectionResource<ParameterResource, TParameter> {
+
+ private static final Logger logger = LoggerFactory.getLogger(ParametersResource.class);
+
+
+ public ParametersResource(List<TParameter> parameters, IPersistable typeResource) {
+ super(ParameterResource.class, TParameter.class, parameters, typeResource);
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.TEXT_PLAIN)
+ // @formatter:off
+ public Response createParamter(
+ @FormParam("name") String name,
+ @FormParam("type") String type,
+ @FormParam("required") @RestDocParam(description="type tYesNo, not Boolean. For convenience, on/off is also supported. In case this parameter is not provided, 'off' is assumed. This is in contrast to the specification, but it eases implementing the UI") String required) {
+ // @formatter:on
+ if (StringUtils.isEmpty(name)) {
+ return Response.status(Status.BAD_REQUEST).entity("name must not be null").build();
+ }
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).entity("type must not be null").build();
+ }
+
+ TParameter param = new TParameter();
+ param.setName(name);
+ param.setType(type);
+ TBoolean tb;
+ if (required == null) {
+ // The specification states that the default value is "yes"
+ // We assume "no", because Chrome does not send the checkbox data if a checkbox is not checked
+ tb = TBoolean.NO;
+ } else {
+ if (required.equalsIgnoreCase("on")) {
+ tb = TBoolean.YES;
+ } else if (required.equalsIgnoreCase("off")) {
+ tb = TBoolean.NO;
+ } else {
+ try {
+ tb = TBoolean.valueOf(required);
+ } catch (java.lang.IllegalArgumentException e) {
+ return Response.status(Status.BAD_REQUEST).entity("Wrong format of required").build();
+ }
+ }
+ }
+ param.setRequired(tb);
+
+ this.list.add(param);
+
+ return BackendUtils.persist(this.res);
+ }
+
+ @Override
+ public String getId(TParameter entity) {
+ return entity.getName();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java
new file mode 100644
index 0000000..ea94a21
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/package-info.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+/**
+ * This package contains the REST resources
+ *
+ * Mostly, they produces Viewables, where a JSP and the current resource is
+ * passed As the JSP itself handles plain Java objects and not Responses, the
+ * resources have also methods returning POJOs. This might be ugly design, but
+ * was quick to implement.
+ *
+ * The package structure is mirrored in src/main/webapp/jsp to ease finding the
+ * JSPs belonging to a resource.
+ *
+ * The resources are <em>not</em> in line with the resource model of the TOSCA
+ * container. Especially, we do not employ HATEOAS here.
+ */
+package org.eclipse.winery.repository.resources;
+
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java
new file mode 100644
index 0000000..6a249df
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplateResource.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
+import org.eclipse.winery.model.tosca.TExtensibleElements;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
+import org.eclipse.winery.model.tosca.TPlans;
+import org.eclipse.winery.model.tosca.TServiceTemplate;
+import org.eclipse.winery.model.tosca.TTopologyTemplate;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.AbstractComponentInstanceWithReferencesResource;
+import org.eclipse.winery.repository.resources.IHasName;
+import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.BoundaryDefinitionsResource;
+import org.eclipse.winery.repository.resources.servicetemplates.plans.PlansResource;
+import org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal.SelfServicePortalResource;
+import org.eclipse.winery.repository.resources.servicetemplates.topologytemplates.TopologyTemplateResource;
+import org.restdoc.annotations.RestDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServiceTemplateResource extends AbstractComponentInstanceWithReferencesResource implements IHasName {
+
+ private static final Logger logger = LoggerFactory.getLogger(ServiceTemplateResource.class);
+
+
+ public ServiceTemplateResource(ServiceTemplateId id) {
+ super(id);
+ }
+
+ /** sub-resources **/
+
+ @Path("topologytemplate/")
+ public TopologyTemplateResource getTopologyTemplateResource() {
+ if (this.getServiceTemplate().getTopologyTemplate() == null) {
+ // the main service template resource exists
+ // default topology template: empty template
+ // This eases the JSPs etc. and is valid as a non-existant topology template is equal to an empty one
+ this.getServiceTemplate().setTopologyTemplate(new TTopologyTemplate());
+ }
+ return new TopologyTemplateResource(this);
+ }
+
+ @Path("plans/")
+ public PlansResource getPlansResource() {
+ TPlans plans = this.getServiceTemplate().getPlans();
+ if (plans == null) {
+ plans = new TPlans();
+ this.getServiceTemplate().setPlans(plans);
+ }
+ return new PlansResource(plans.getPlan(), this);
+ }
+
+ @Path("selfserviceportal/")
+ public SelfServicePortalResource getSelfServicePortalResource() {
+ return new SelfServicePortalResource(this);
+ }
+
+ @Path("boundarydefinitions/")
+ public BoundaryDefinitionsResource getBoundaryDefinitionsResource() {
+ TBoundaryDefinitions boundaryDefinitions = this.getServiceTemplate().getBoundaryDefinitions();
+ if (boundaryDefinitions == null) {
+ boundaryDefinitions = new TBoundaryDefinitions();
+ this.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions);
+ }
+ return new BoundaryDefinitionsResource(this, boundaryDefinitions);
+ }
+
+ @Override
+ public String getName() {
+ String name = this.getServiceTemplate().getName();
+ if (name == null) {
+ // place default
+ name = this.getId().getXmlId().getDecoded();
+ }
+ return name;
+ }
+
+ @Override
+ public Response setName(String name) {
+ this.getServiceTemplate().setName(name);
+ return BackendUtils.persist(this);
+ }
+
+ // @formatter:off
+ @GET
+ @RestDoc(methodDescription="Returns the associated node type, which can be substituted by this service template.<br />" +
+ "@return a QName of the form {namespace}localName is returned.")
+ @Path("substitutableNodeType")
+ @Produces(MediaType.TEXT_PLAIN)
+ // @formatter:on
+ public Response getSubstitutableNodeTypeAsResponse() {
+ QName qname = this.getServiceTemplate().getSubstitutableNodeType();
+ if (qname == null) {
+ return Response.status(Status.NOT_FOUND).build();
+ } else {
+ return Response.ok(qname.toString()).build();
+ }
+ }
+
+ /**
+ *
+ * @return null if there is no substitutable node type
+ */
+ public QName getSubstitutableNodeType() {
+ return this.getServiceTemplate().getSubstitutableNodeType();
+ }
+
+ @DELETE
+ @RestDoc(methodDescription = "Removes the association to substitutable node type")
+ @Path("substitutableNodeType")
+ public Response deleteSubstitutableNodeType() {
+ this.getServiceTemplate().setSubstitutableNodeType(null);
+ BackendUtils.persist(this);
+ return Response.noContent().build();
+ }
+
+ public TServiceTemplate getServiceTemplate() {
+ return (TServiceTemplate) this.getElement();
+ }
+
+ @Override
+ protected TExtensibleElements createNewElement() {
+ return new TServiceTemplate();
+ }
+
+ @Override
+ protected void copyIdToFields() {
+ this.getServiceTemplate().setId(this.getId().getXmlId().getDecoded());
+ this.getServiceTemplate().setTargetNamespace(this.getId().getNamespace().getDecoded());
+ }
+
+ /**
+ * Synchronizes the known plans with the data in the XML. When there is a
+ * stored file, but no known entry in the XML, we guess "BPEL" as language
+ * and "build plan" as type.
+ *
+ * @throws IOException
+ */
+ @Override
+ public void synchronizeReferences() {
+ // locally stored plans
+ TPlans plans = this.getServiceTemplate().getPlans();
+
+ // plans stored in the repository
+ PlansId plansContainerId = new PlansId((ServiceTemplateId) this.getId());
+ SortedSet<PlanId> nestedPlans = Repository.INSTANCE.getNestedIds(plansContainerId, PlanId.class);
+
+ Set<PlanId> plansToAdd = new HashSet<PlanId>();
+ plansToAdd.addAll(nestedPlans);
+
+ if (nestedPlans.isEmpty()) {
+ if (plans == null) {
+ // data on the file system equals the data -> no plans
+ return;
+ } else {
+ // we have to check for equality later
+ }
+ }
+
+ if (plans == null) {
+ plans = new TPlans();
+ this.getServiceTemplate().setPlans(plans);
+ }
+
+ for (Iterator<TPlan> iterator = plans.getPlan().iterator(); iterator.hasNext();) {
+ TPlan plan = iterator.next();
+ if (plan.getPlanModel() != null) {
+ // in case, a plan is directly contained in a Model element, we do not need to do anything
+ continue;
+ }
+ PlanModelReference planModelReference = plan.getPlanModelReference();
+ if ((planModelReference = plan.getPlanModelReference()) != null) {
+ String ref = planModelReference.getReference();
+ if ((ref == null) || ref.startsWith("../")) {
+ // references to local plans start with "../"
+ // special case (due to errors in the importer): empty PlanModelReference field
+ if (plan.getId() == null) {
+ // invalid plan entry: no id.
+ // we remove the entry
+ iterator.remove();
+ continue;
+ }
+ PlanId planId = new PlanId(plansContainerId, new XMLId(plan.getId(), false));
+ if (nestedPlans.contains(planId)) {
+ // everything allright
+ // we do NOT need to add the plan on the HDD to the XML
+ plansToAdd.remove(planId);
+ } else {
+ // no local storage for the plan, we remove it from the XML
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ // add all plans locally stored, but not contained in the XML, as plan element to the plans of the service template.
+ List<TPlan> thePlans = plans.getPlan();
+ for (PlanId planId : plansToAdd) {
+ SortedSet<RepositoryFileReference> files = Repository.INSTANCE.getContainedFiles(planId);
+ if (files.size() != 1) {
+ throw new IllegalStateException("Currently, only one file per plan is supported.");
+ }
+ RepositoryFileReference ref = files.iterator().next();
+
+ TPlan plan = new TPlan();
+ plan.setId(planId.getXmlId().getDecoded());
+ plan.setName(planId.getXmlId().getDecoded());
+ plan.setPlanType(org.eclipse.winery.repository.Constants.TOSCA_PLANTYPE_BUILD_PLAN);
+ plan.setPlanLanguage(org.eclipse.winery.common.constants.Namespaces.URI_BPEL20_EXECUTABLE);
+
+ // create a PlanModelReferenceElement pointing to that file
+ String path = Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(ref));
+ // path is relative from the definitions element
+ path = "../" + path;
+ PlanModelReference pref = new PlanModelReference();
+ pref.setReference(path);
+
+ plan.setPlanModelReference(pref);
+ thePlans.add(plan);
+ }
+
+ try {
+ this.persist();
+ } catch (IOException e) {
+ throw new IllegalStateException("Could not persist resource", e);
+ }
+ return;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java
new file mode 100644
index 0000000..fd8b82c
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/ServiceTemplatesResource.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates;
+
+import org.eclipse.winery.repository.resources.AbstractComponentsResource;
+
+public class ServiceTemplatesResource extends AbstractComponentsResource<ServiceTemplateResource> {
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java
new file mode 100644
index 0000000..0d4b141
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsJSPData.java
@@ -0,0 +1,113 @@
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.xml.namespace.QName;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.apache.taglibs.standard.functions.Functions;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.ids.definitions.PolicyTypeId;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlans;
+import org.eclipse.winery.model.tosca.TServiceTemplate;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.TypeWithShortName;
+import org.eclipse.winery.repository.datatypes.select2.Select2DataItem;
+import org.eclipse.winery.repository.resources.admin.types.ConstraintTypesManager;
+
+public class BoundaryDefinitionsJSPData {
+
+ private final TServiceTemplate ste;
+ private final TBoundaryDefinitions defs;
+ private URI baseURI;
+
+
+ /**
+ *
+ * @param ste the service template of the boundary definitions. Required to
+ * get a list of all plans
+ * @param baseURI the base URI of the service. Requried for rendering the
+ * topology template for the selections
+ */
+ public BoundaryDefinitionsJSPData(TServiceTemplate ste, URI baseURI) {
+ this.ste = ste;
+ this.defs = ste.getBoundaryDefinitions();
+ this.baseURI = baseURI;
+ }
+
+ private String getDefinedProperties() {
+ Properties p = ModelUtilities.getProperties(this.defs);
+ Object o = p.getAny();
+ if (o == null) {
+ // nothing stored -> return empty string
+ return "";
+ } else {
+ // something stored --> return that
+ return Utils.getXMLAsString(p.getAny());
+ }
+ }
+
+ /**
+ * Helper method to return an initialized properties object only containing
+ * the user-defined properties. The TOSCA properties-element is not returned
+ * as the TOSCA XSD allows a single element only
+ */
+ public String getDefinedPropertiesAsEscapedHTML() {
+ String s = this.getDefinedProperties();
+ s = StringEscapeUtils.escapeHtml4(s);
+ return s;
+ }
+
+ public String getDefinedPropertiesAsJSONString() {
+ String s = this.getDefinedProperties();
+ s = StringEscapeUtils.escapeEcmaScript(s);
+ return s;
+ }
+
+ public TBoundaryDefinitions getDefs() {
+ return this.defs;
+ }
+
+ public String getBoundaryDefinitionsAsXMLStringEncoded() {
+ String res = Utils.getXMLAsString(this.defs);
+ return Functions.escapeXml(res);
+ }
+
+ public Collection<TypeWithShortName> getConstraintTypes() {
+ return ConstraintTypesManager.INSTANCE.getTypes();
+ }
+
+ public Collection<QName> getAllPolicyTypes() {
+ SortedSet<PolicyTypeId> allTOSCAComponentIds = Repository.INSTANCE.getAllTOSCAComponentIds(PolicyTypeId.class);
+ return BackendUtils.convertTOSCAComponentIdCollectionToQNameCollection(allTOSCAComponentIds);
+ }
+
+ public String getRepositoryURL() {
+ return this.baseURI.toString();
+ }
+
+ public List<Select2DataItem> getlistOfAllPlans() {
+ TPlans plans = this.ste.getPlans();
+ if (plans == null) {
+ return null;
+ } else {
+ List<Select2DataItem> res = new ArrayList<>(plans.getPlan().size());
+ for (TPlan plan : plans.getPlan()) {
+ String id = plan.getId();
+ String name = ModelUtilities.getNameWithIdFallBack(plan);
+ Select2DataItem di = new Select2DataItem(id, name);
+ res.add(di);
+ }
+ return res;
+ }
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java
new file mode 100644
index 0000000..58dfbe9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/BoundaryDefinitionsResource.java
@@ -0,0 +1,144 @@
+/*******************************************************************************
+ * Copyright (c) 2013-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Capabilities;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Interfaces;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Policies;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties.PropertyMappings;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Requirements;
+import org.eclipse.winery.model.tosca.TCapabilityRef;
+import org.eclipse.winery.model.tosca.TRequirementRef;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces.InterfacesResource;
+import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies.PoliciesResource;
+import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.CapabilitiesResource;
+import org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.w3c.dom.Document;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class BoundaryDefinitionsResource {
+
+ private final ServiceTemplateResource serviceTemplateResource;
+ private final TBoundaryDefinitions boundaryDefinitions;
+
+
+ public BoundaryDefinitionsResource(ServiceTemplateResource serviceTemplateResource, TBoundaryDefinitions boundaryDefinitions) {
+ this.serviceTemplateResource = serviceTemplateResource;
+ this.boundaryDefinitions = boundaryDefinitions;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML(@Context UriInfo uriInfo) {
+ return new Viewable("/jsp/servicetemplates/boundarydefinitions/boundarydefinitions.jsp", new BoundaryDefinitionsJSPData(this.serviceTemplateResource.getServiceTemplate(), uriInfo.getBaseUri()));
+ }
+
+ @PUT
+ @RestDoc(methodDescription = "Replaces the boundary definitions by the information given in the XML")
+ @Consumes(MediaType.TEXT_XML)
+ public Response setModel(TBoundaryDefinitions boundaryDefinitions) {
+ this.serviceTemplateResource.getServiceTemplate().setBoundaryDefinitions(boundaryDefinitions);
+ return BackendUtils.persist(this.serviceTemplateResource);
+ }
+
+ @Path("properties/")
+ @PUT
+ @Consumes(MediaType.TEXT_XML)
+ @RestDoc(resourceDescription = "Models the user-defined properties. The property mappings go into a separate resource propertymappings.")
+ public Response putProperties(@RestDocParam(description = "Stored properties. The XSD allows a single element only. Therefore, we go for the contained element") Document doc) {
+ org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties properties = ModelUtilities.getProperties(this.boundaryDefinitions);
+ properties.setAny(doc.getDocumentElement());
+ return BackendUtils.persist(this.serviceTemplateResource);
+ }
+
+ @Path("requirements/")
+ public RequirementsResource getRequiremensResource() {
+ Requirements requirements = this.boundaryDefinitions.getRequirements();
+ if (requirements == null) {
+ requirements = new Requirements();
+ this.boundaryDefinitions.setRequirements(requirements);
+ }
+ List<TRequirementRef> refs = requirements.getRequirement();
+ return new RequirementsResource(this.serviceTemplateResource, refs);
+ }
+
+ @Path("capabilities/")
+ public CapabilitiesResource getCapabilitiesResource() {
+ Capabilities caps = this.boundaryDefinitions.getCapabilities();
+ if (caps == null) {
+ caps = new Capabilities();
+ this.boundaryDefinitions.setCapabilities(caps);
+ }
+ List<TCapabilityRef> refs = caps.getCapability();
+ return new CapabilitiesResource(this.serviceTemplateResource, refs);
+ }
+
+ @Path("policies/")
+ public PoliciesResource getPoliciesResource() {
+ Policies policies = this.boundaryDefinitions.getPolicies();
+ if (policies == null) {
+ policies = new Policies();
+ this.boundaryDefinitions.setPolicies(policies);
+ }
+ return new PoliciesResource(policies.getPolicy(), this.serviceTemplateResource);
+ }
+
+ /**
+ * This path is below "boundary definitions" to ease implementation If it
+ * was modeled following the XSD, it would have been nested below
+ * "properties". We did not do that
+ */
+ @Path("propertymappings/")
+ public PropertyMappingsResource getPropertyMappings() {
+ Properties properties = this.boundaryDefinitions.getProperties();
+ if (properties == null) {
+ properties = new Properties();
+ this.boundaryDefinitions.setProperties(properties);
+ }
+ PropertyMappings propertyMappings = properties.getPropertyMappings();
+ if (propertyMappings == null) {
+ propertyMappings = new PropertyMappings();
+ properties.setPropertyMappings(propertyMappings);
+ }
+ return new PropertyMappingsResource(propertyMappings, this.serviceTemplateResource);
+ }
+
+ @Path("interfaces/")
+ public InterfacesResource getInterfacesResource() {
+ Interfaces interfaces = this.boundaryDefinitions.getInterfaces();
+ if (interfaces == null) {
+ interfaces = new Interfaces();
+ this.boundaryDefinitions.setInterfaces(interfaces);
+ }
+ return new InterfacesResource(interfaces.getInterface(), this.serviceTemplateResource);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java
new file mode 100644
index 0000000..a6872e0
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/PropertyMappingsResource.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2013-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions;
+
+import java.util.Iterator;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.model.tosca.TBoundaryDefinitions.Properties.PropertyMappings;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TPropertyMapping;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.restdoc.annotations.RestDoc;
+
+public class PropertyMappingsResource {
+
+ private final PropertyMappings propertyMappings;
+ private final ServiceTemplateResource res;
+
+
+ public PropertyMappingsResource(PropertyMappings propertyMappings, ServiceTemplateResource res) {
+ this.propertyMappings = propertyMappings;
+ this.res = res;
+ }
+
+ @Path("{serviceTemplatePropertyRef}")
+ @DELETE
+ public Response onDelete(@PathParam("serviceTemplatePropertyRef") String serviceTemplatePropertyRef) {
+ serviceTemplatePropertyRef = Util.URLdecode(serviceTemplatePropertyRef);
+ Iterator<TPropertyMapping> iterator = this.propertyMappings.getPropertyMapping().iterator();
+ while (iterator.hasNext()) {
+ TPropertyMapping propertyMapping = iterator.next();
+ if (propertyMapping.getServiceTemplatePropertyRef().equals(serviceTemplatePropertyRef)) {
+ iterator.remove();
+ return BackendUtils.persist(this.res);
+ }
+ }
+ // if the property mapping was not found, we reach this point
+ // otherwise "iterator.remove()" has called and the resource persisted
+ return Response.status(Status.NOT_FOUND).build();
+ }
+
+ private void updatePropertyMapping(TPropertyMapping propertyMapping, String serviceTemplatePropertyRef, TEntityTemplate template, String targetPropertyRef) {
+ propertyMapping.setServiceTemplatePropertyRef(serviceTemplatePropertyRef);
+ propertyMapping.setTargetObjectRef(template);
+ propertyMapping.setTargetPropertyRef(targetPropertyRef);
+ }
+
+ @RestDoc(methodDescription = "Creates or updates a property mapping with the given fields")
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ // @formatter:off
+ public Response onPost(
+ @FormParam("serviceTemplatePropertyRef") String serviceTemplatePropertyRef,
+ @FormParam("targetObjectRef") String targetObjectRef,
+ @FormParam("targetPropertyRef") String targetPropertyRef
+ ) {
+ // @formatter:on
+ if (StringUtils.isEmpty(serviceTemplatePropertyRef)) {
+ return Response.status(Status.BAD_REQUEST).entity("serviceTemplatePropertyRef must not be empty").build();
+ }
+ if (StringUtils.isEmpty(targetObjectRef)) {
+ return Response.status(Status.BAD_REQUEST).entity("targetObjectRef must not be empty").build();
+ }
+ if (StringUtils.isEmpty(targetPropertyRef)) {
+ return Response.status(Status.BAD_REQUEST).entity("targetPropertyRef must not be empty").build();
+ }
+
+ TEntityTemplate template = ModelUtilities.findNodeTemplateOrRequirementOfNodeTemplateOrCapabilityOfNodeTemplateOrRelationshipTemplate(this.res.getServiceTemplate().getTopologyTemplate(), targetObjectRef);
+ if (template == null) {
+ return Response.status(Status.BAD_REQUEST).entity("targetObjectRef " + targetObjectRef + " could not be resolved.").build();
+ }
+
+ // replace propertyMapping if it exists
+ Iterator<TPropertyMapping> iterator = this.propertyMappings.getPropertyMapping().iterator();
+ while (iterator.hasNext()) {
+ TPropertyMapping propertyMapping = iterator.next();
+ if (propertyMapping.getServiceTemplatePropertyRef().equals(serviceTemplatePropertyRef)) {
+ // we found a property with the same mapping
+ // just update it ...
+ this.updatePropertyMapping(propertyMapping, serviceTemplatePropertyRef, template, targetPropertyRef);
+ // ... and finish processing
+ return BackendUtils.persist(this.res);
+ }
+ }
+
+ // the property mapping didn't exist,
+ // we create a new one
+ TPropertyMapping newPropertyMapping = new TPropertyMapping();
+ this.updatePropertyMapping(newPropertyMapping, serviceTemplatePropertyRef, template, targetPropertyRef);
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java
new file mode 100644
index 0000000..b69e802
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedInterfaceResource.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces;
+
+import java.util.List;
+
+import javax.ws.rs.Path;
+
+import org.eclipse.winery.model.tosca.TExportedInterface;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+
+public class ExportedInterfaceResource extends EntityWithIdResource<TExportedInterface> {
+
+ public ExportedInterfaceResource(IIdDetermination<TExportedInterface> idDetermination, TExportedInterface o, int idx, List<TExportedInterface> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ @Path("exportedoperations/")
+ public ExportedOperationsResource getExportedOperationsResource() {
+ return new ExportedOperationsResource(this.o.getOperation(), this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java
new file mode 100644
index 0000000..dd10751
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationResource.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces;
+
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.model.tosca.TExportedOperation;
+import org.eclipse.winery.model.tosca.TExportedOperation.NodeOperation;
+import org.eclipse.winery.model.tosca.TExportedOperation.Plan;
+import org.eclipse.winery.model.tosca.TExportedOperation.RelationshipOperation;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.model.tosca.TServiceTemplate;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+public class ExportedOperationResource extends EntityWithIdResource<TExportedOperation> {
+
+ private static final Logger logger = LoggerFactory.getLogger(ExportedOperationResource.class);
+
+
+ public ExportedOperationResource(IIdDetermination<TExportedOperation> idDetermination, TExportedOperation o, int idx, List<TExportedOperation> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ public String getJSONRepresentation() {
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter sw = new StringWriter();
+ try {
+ JsonGenerator jg = jsonFactory.createGenerator(sw);
+ jg.writeStartObject();
+ String type = this.getType();
+ jg.writeStringField("type", type);
+ jg.writeStringField("ref", this.getReference());
+ if ((type != null) && (!type.equals("Plan"))) {
+ jg.writeStringField("interfacename", this.getInterfaceName());
+ jg.writeStringField("operationname", this.getOperationName());
+ }
+ jg.writeEndObject();
+ jg.close();
+ } catch (Exception e) {
+ ExportedOperationResource.logger.error(e.getMessage(), e);
+ throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(e).build());
+ }
+ String res = sw.toString();
+ return res;
+ }
+
+ /**
+ *
+ * @return "NodeOperation" | "RelationshipOperation" | "Plan" | null. null
+ * is returned if no type is set
+ */
+ @Path("type")
+ @GET
+ public String getType() {
+ if (this.o.getNodeOperation() != null) {
+ return "NodeOperation";
+ } else if (this.o.getRelationshipOperation() != null) {
+ return "RelationshipOperation";
+ } else if (this.o.getPlan() != null) {
+ return "Plan";
+ } else {
+ return null;
+ }
+ }
+
+ @Path("type")
+ @PUT
+ public Response setType(String type) {
+ switch (type) {
+ case "NodeOperation":
+ if (this.o.getNodeOperation() == null) {
+ // only do something, if the type is really changed
+ this.o.setRelationshipOperation(null);
+ this.o.setPlan(null);
+ NodeOperation no = new NodeOperation();
+ this.o.setNodeOperation(no);
+ }
+ break;
+ case "RelationshipOperation":
+ if (this.o.getRelationshipOperation() == null) {
+ // only do something, if the type is really changed
+ this.o.setNodeOperation(null);
+ this.o.setPlan(null);
+ RelationshipOperation ro = new RelationshipOperation();
+ this.o.setRelationshipOperation(ro);
+ }
+ break;
+ case "Plan":
+ if (this.o.getPlan() == null) {
+ // only do something, if the type is really changed
+ this.o.setNodeOperation(null);
+ this.o.setRelationshipOperation(null);
+ Plan plan = new Plan();
+ this.o.setPlan(plan);
+ }
+ break;
+ default:
+ return Response.status(Status.BAD_REQUEST).entity("Unknown type " + type).build();
+ }
+ return BackendUtils.persist(this.res);
+ }
+
+ /**
+ * @return null if no reference is set
+ */
+ @Path("ref")
+ @GET
+ public String getReference() {
+ if (this.o.getNodeOperation() != null) {
+ TNodeTemplate nt = (TNodeTemplate) this.o.getNodeOperation().getNodeRef();
+ if (nt == null) {
+ return null;
+ }
+ return nt.getId();
+ } else if (this.o.getRelationshipOperation() != null) {
+ TRelationshipTemplate rt = (TRelationshipTemplate) this.o.getRelationshipOperation().getRelationshipRef();
+ if (rt == null) {
+ return null;
+ }
+ return rt.getId();
+ } else if (this.o.getPlan() != null) {
+ TPlan plan = (TPlan) this.o.getPlan().getPlanRef();
+ if (plan == null) {
+ return null;
+ }
+ return plan.getId();
+ } else {
+ // no type set -> no reference can be returned
+ return null;
+ }
+ }
+
+ @Path("ref")
+ @PUT
+ public Response setReference(String ref) {
+ TServiceTemplate ste = ((ServiceTemplateResource) this.res).getServiceTemplate();
+
+ // we assume that a correctly set type also means that getX (getNodeOperation, ...) returns non null
+ switch (this.getType()) {
+ case "NodeOperation":
+ TNodeTemplate nodeTemplate = ModelUtilities.resolveNodeTemplate(ste, ref);
+ this.o.getNodeOperation().setNodeRef(nodeTemplate);
+ break;
+ case "RelationshipOperation":
+ TRelationshipTemplate relationshipTemplate = ModelUtilities.resolveRelationshipTemplate(ste, ref);
+ this.o.getRelationshipOperation().setRelationshipRef(relationshipTemplate);
+ break;
+ case "Plan":
+ TPlan plan = ModelUtilities.resolvePlan(ste, ref);
+ this.o.getPlan().setPlanRef(plan);
+ break;
+ default:
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unknown type " + this.getType()).build();
+ }
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("interfacename")
+ @GET
+ public String getInterfaceName() {
+ if (this.o.getNodeOperation() != null) {
+ return this.o.getNodeOperation().getInterfaceName();
+ } else if (this.o.getRelationshipOperation() != null) {
+ return this.o.getRelationshipOperation().getInterfaceName();
+ } else if (this.o.getPlan() != null) {
+ throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an interface").build());
+ } else {
+ throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unsupported state of ExportedOperation").build());
+ }
+ }
+
+ @Path("interfacename")
+ @PUT
+ public Response setInterfaceName(String interfacename) {
+ if (this.o.getNodeOperation() != null) {
+ this.o.getNodeOperation().setInterfaceName(interfacename);
+ } else if (this.o.getRelationshipOperation() != null) {
+ this.o.getRelationshipOperation().setInterfaceName(interfacename);
+ } else if (this.o.getPlan() != null) {
+ throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an interface").build());
+ } else {
+ throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("No type set").build());
+ }
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("operationname")
+ @GET
+ public String getOperationName() {
+ if (this.o.getNodeOperation() != null) {
+ return this.o.getNodeOperation().getOperationName();
+ } else if (this.o.getRelationshipOperation() != null) {
+ return this.o.getRelationshipOperation().getOperationName();
+ } else if (this.o.getPlan() != null) {
+ throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an operation").build());
+ } else {
+ throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity("Unsupported state of ExportedOperation").build());
+ }
+ }
+
+ @Path("operationname")
+ @PUT
+ public Response setOperationName(String name) {
+ if (this.o.getNodeOperation() != null) {
+ this.o.getNodeOperation().setOperationName(name);
+ } else if (this.o.getRelationshipOperation() != null) {
+ this.o.getRelationshipOperation().setOperationName(name);
+ } else if (this.o.getPlan() != null) {
+ throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("A plan does not carry an operation").build());
+ } else {
+ throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("No type set").build());
+ }
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java
new file mode 100644
index 0000000..d8788fd
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/ExportedOperationsResource.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TExportedOperation;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class ExportedOperationsResource extends EntityWithIdCollectionResource<ExportedOperationResource, TExportedOperation> {
+
+ public ExportedOperationsResource(List<TExportedOperation> list, IPersistable res) {
+ super(ExportedOperationResource.class, TExportedOperation.class, list, res);
+ }
+
+ @Override
+ public String getId(TExportedOperation entity) {
+ return entity.getName();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("No implementation required: boundarydefinitions.jsp contains all required html.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java
new file mode 100644
index 0000000..301f457
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/InterfacesResource.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TExportedInterface;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class InterfacesResource extends EntityWithIdCollectionResource<ExportedInterfaceResource, TExportedInterface> {
+
+ public InterfacesResource(List<TExportedInterface> list, IPersistable res) {
+ super(ExportedInterfaceResource.class, TExportedInterface.class, list, res);
+ }
+
+ @Override
+ public String getId(TExportedInterface entity) {
+ return entity.getName();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("No implementation required: boundarydefinitions.jsp contains all required html.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java
new file mode 100644
index 0000000..6a342ea
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/interfaces/package-info.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+/**
+ * This package models exported interfaces nested in a boundary definitions.
+ */
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.interfaces; \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java
new file mode 100644
index 0000000..b18341f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PoliciesResource.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies;
+
+import java.util.List;
+
+import javax.ws.rs.PUT;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.winery.model.tosca.TPolicy;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class PoliciesResource extends EntityWithoutIdCollectionResource<PolicyResource, TPolicy> {
+
+ public PoliciesResource(List<TPolicy> list, IPersistable res) {
+ super(PolicyResource.class, TPolicy.class, list, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not required: boundarydefinitions.jsp also includes the content of the Policy tab.");
+ }
+
+ @PUT
+ public Response replaceAll(List<TPolicy> newList) {
+ this.list.clear();
+ for (TPolicy policy : newList) {
+ this.list.add(policy);
+ }
+ return BackendUtils.persist(this.res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java
new file mode 100644
index 0000000..08fbd8d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/PolicyResource.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TPolicy;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource;
+
+public class PolicyResource extends EntityWithoutIdResource<TPolicy> {
+
+ public PolicyResource(TPolicy o, int idx, List<TPolicy> list, IPersistable res) {
+ super(o, idx, list, res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java
new file mode 100644
index 0000000..45bc0c7
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/policies/package-info.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+/**
+ * This package models policies nested in a boundary definitions. It could be resued for the topology modeler, but currently, this is not necessary.
+ */
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.policies; \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java
new file mode 100644
index 0000000..80f2640
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilitiesResource.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.model.tosca.TCapability;
+import org.eclipse.winery.model.tosca.TCapabilityRef;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * This class is an adaption from
+ * {@link org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.RequirementsResource}
+ */
+public class CapabilitiesResource extends EntityWithoutIdCollectionResource<CapabilityResource, TCapabilityRef> {
+
+ public CapabilitiesResource(IPersistable res, List<TCapabilityRef> refs) {
+ super(CapabilityResource.class, TCapabilityRef.class, refs, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not yet required: boundarydefinitions.jsp renders all tab content.");
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response addNewElement(@FormParam("name") String name, @FormParam("ref") String reference) {
+ // Implementation adapted from super addNewElement
+
+ if (reference == null) {
+ return Response.status(Status.BAD_REQUEST).entity("A reference has to be provided").build();
+ }
+
+ TCapabilityRef ref = new TCapabilityRef();
+ ref.setName(name); // may also be null
+
+ // The XML model fordces us to put a reference to the object and not just the string
+ ServiceTemplateResource rs = (ServiceTemplateResource) this.res;
+ TCapability resolved = ModelUtilities.resolveCapability(rs.getServiceTemplate(), reference);
+ // In case nothing was found: report back to the user
+ if (resolved == null) {
+ return Response.status(Status.BAD_REQUEST).entity("Reference could not be resolved").build();
+ }
+
+ ref.setRef(resolved);
+
+ // "this.alreadyContains(ref)" cannot be called as this leads to a mappable exception: The data does not contain an id where the given ref attribute may point to
+
+ this.list.add(ref);
+ return CollectionsHelper.persist(this.res, this, ref);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java
new file mode 100644
index 0000000..7cb7b49
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/CapabilityResource.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TCapabilityRef;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource;
+
+public class CapabilityResource extends EntityWithoutIdResource<TCapabilityRef> {
+
+ public CapabilityResource(TCapabilityRef o, int idx, List<TCapabilityRef> list, IPersistable res) {
+ super(o, idx, list, res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java
new file mode 100644
index 0000000..72a7476
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementResource.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TRequirementRef;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdResource;
+
+public class RequirementResource extends EntityWithoutIdResource<TRequirementRef> {
+
+ public RequirementResource(TRequirementRef o, int idx, List<TRequirementRef> list, IPersistable res) {
+ super(o, idx, list, res);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java
new file mode 100644
index 0000000..dc6ad94
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/RequirementsResource.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.ModelUtilities;
+import org.eclipse.winery.model.tosca.TRequirement;
+import org.eclipse.winery.model.tosca.TRequirementRef;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.CollectionsHelper;
+import org.eclipse.winery.repository.resources._support.collections.withoutid.EntityWithoutIdCollectionResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+/**
+ * This class is mirrored at
+ * {@link org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps.CapabilitiesResource}
+ */
+public class RequirementsResource extends EntityWithoutIdCollectionResource<RequirementResource, TRequirementRef> {
+
+ public RequirementsResource(IPersistable res, List<TRequirementRef> refs) {
+ super(RequirementResource.class, TRequirementRef.class, refs, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not yet required: boundarydefinitions.jsp renders all tab content.");
+ }
+
+ /**
+ * Adds an element using form-encoding
+ *
+ * This is necessary as TRequirementRef contains an IDREF and the XML
+ * snippet itself does not contain the target id
+ *
+ * @param name the optional name of the requirement
+ * @param reference the reference to a requirement in the topology
+ */
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response addNewElement(@FormParam("name") String name, @FormParam("ref") String reference) {
+ // Implementation adapted from super addNewElement
+
+ if (reference == null) {
+ return Response.status(Status.BAD_REQUEST).entity("A reference has to be provided").build();
+ }
+
+ TRequirementRef ref = new TRequirementRef();
+ ref.setName(name); // may also be null
+
+ // The XML model forces us to put a reference to the object and not just the string
+ ServiceTemplateResource rs = (ServiceTemplateResource) this.res;
+ TRequirement resolved = ModelUtilities.resolveRequirement(rs.getServiceTemplate(), reference);
+ // In case nothing was found: report back to the user
+ if (resolved == null) {
+ return Response.status(Status.BAD_REQUEST).entity("Reference could not be resolved").build();
+ }
+
+ ref.setRef(resolved);
+
+ // "this.alreadyContains(ref)" cannot be called as this leads to a mappable exception: The data does not contain an id where the given ref attribute may point to
+
+ this.list.add(ref);
+ return CollectionsHelper.persist(this.res, this, ref);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java
new file mode 100644
index 0000000..f6a3c5d
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/boundarydefinitions/reqscaps/package-info.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+/**
+ * This package contains all classes for requirement refs and capability refs
+ *
+ * They are nested as "Requirements" / "Capabilities" in the boundary definitions, but the things itself are called "...Ref"
+ */
+package org.eclipse.winery.repository.resources.servicetemplates.boundarydefinitions.reqscaps; \ No newline at end of file
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java
new file mode 100644
index 0000000..5a4b56f
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanFileResource.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2014-2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.plans;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.restdoc.annotations.RestDoc;
+
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+public class PlanFileResource {
+
+ private final PlanId planId;
+ private TPlan plan;
+ private ServiceTemplateResource res;
+
+
+ public PlanFileResource(ServiceTemplateResource res, PlanId planId, TPlan plan) {
+ this.res = res;
+ this.planId = planId;
+ this.plan = plan;
+ }
+
+ /**
+ * Extracts the file reference from plan's planModelReference
+ */
+ private RepositoryFileReference getFileRef() {
+ String reference = this.plan.getPlanModelReference().getReference();
+ File f = new File(reference);
+ return new RepositoryFileReference(this.planId, f.getName());
+ }
+
+ @PUT
+ @Consumes({MediaType.MULTIPART_FORM_DATA})
+ @RestDoc(methodDescription = "Resource currently works for BPMN4TOSCA plans only")
+ // @formatter:off
+ public Response onPutFile(
+ @FormDataParam("file") InputStream uploadedInputStream,
+ @FormDataParam("file") FormDataContentDisposition fileDetail,
+ @FormDataParam("file") FormDataBodyPart body
+ ) {
+ // @formatter:on
+
+ String fileName = fileDetail.getFileName();
+ RepositoryFileReference ref = new RepositoryFileReference(this.planId, fileName);
+ RepositoryFileReference oldRef = this.getFileRef();
+ boolean persistanceNecessary;
+ if (ref.equals(oldRef)) {
+ // nothing todo, file will be replaced
+ persistanceNecessary = false;
+ } else {
+ // new filename sent
+ BackendUtils.delete(oldRef);
+ PlansResource.setPlanModelReference(this.plan, this.planId, fileName);
+ persistanceNecessary = true;
+ }
+
+ // Really store it
+ try {
+ Repository.INSTANCE.putContentToFile(ref, uploadedInputStream, body.getMediaType());
+ } catch (IOException e1) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not store plan. " + e1.getMessage()).build();
+ }
+
+ if (persistanceNecessary) {
+ return BackendUtils.persist(this.res);
+ } else {
+ return Response.noContent().build();
+ }
+ }
+
+ @PUT
+ @Consumes({MediaType.APPLICATION_JSON})
+ // @formatter:off
+ public Response onPutJSON(InputStream is) {
+ RepositoryFileReference ref = this.getFileRef();
+ return BackendUtils.putContentToFile(ref, is, MediaType.APPLICATION_JSON_TYPE);
+ }
+
+ /**
+ * Returns the stored file.
+ */
+ @GET
+ public Response getFile(@HeaderParam("If-Modified-Since") String modified) {
+ RepositoryFileReference ref = this.getFileRef();
+ return BackendUtils.returnRepoPath(ref, modified);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java
new file mode 100644
index 0000000..704c831
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlanResource.java
@@ -0,0 +1,203 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.plans;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlan.InputParameters;
+import org.eclipse.winery.model.tosca.TPlan.OutputParameters;
+import org.eclipse.winery.repository.Prefs;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources.IHasName;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+import org.eclipse.winery.repository.resources.interfaces.ParametersResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Does <em>not</em> implement
+ * {@link org.eclipse.winery.repository.resources.IHasTypeReference}, because
+ * the type of a plan is outside the system of TOSCA.
+ */
+public class PlanResource extends EntityWithIdResource<TPlan> implements IHasName {
+
+ private static final Logger logger = LoggerFactory.getLogger(PlanResource.class);
+
+
+ public PlanResource(IIdDetermination<TPlan> idDetermination, TPlan o, int idx, List<TPlan> list, ServiceTemplateResource res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ /**
+ * Ugly hack to get the parent service template resource
+ *
+ */
+ public ServiceTemplateResource getServiceTemplateResource() {
+ // Solution proposal 1: Each sub-resource should know its parent service
+ // template
+ //
+ // Solution proposal 2 (Generic solution): Each resource should know its
+ // parent resource
+ //
+ // Does not work when plan is used at as component instance (then,
+ // serviceTemplateResource is null). In this case, a plan is not associated
+ // with a service template.
+
+ // we cannot use "((PlanId) id).getParent()" as this "only" returns an
+ // ID
+ // we could create a newly resource based on that ID
+ // However, the parent resource has already been created when the
+ // PlanResource has been generated:
+ // Jersey crawls down from the main resource through the service
+ // template resource to the plan resource
+ return (ServiceTemplateResource) this.res;
+ }
+
+ /**
+ * Determines the id of the current resource
+ */
+ private PlanId getId() {
+ ServiceTemplateId sId = (ServiceTemplateId) this.getServiceTemplateResource().getId();
+ PlansId psId = new PlansId(sId);
+ PlanId pId = new PlanId(psId, new XMLId(this.o.getId(), false));
+ return pId;
+ }
+
+ @Override
+ @DELETE
+ public Response onDelete() {
+ Response res = super.onDelete();
+ if (Utils.isSuccessFulResponse(res)) {
+ try {
+ Repository.INSTANCE.forceDelete(this.getId());
+ } catch (IOException e) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not remove plan file").build();
+ }
+ return BackendUtils.persist(this.res);
+ } else {
+ return res;
+ }
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Response getHTML(@Context UriInfo uriInfo) {
+ boolean isBPMN4TOSCA = this.o.getPlanLanguage().equals(org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20);
+ String bpmn4toscaBaseURL = Prefs.INSTANCE.getBPMN4TOSCABaseURL();
+ if (isBPMN4TOSCA && (!StringUtils.isEmpty(bpmn4toscaBaseURL))) {
+ String uri = bpmn4toscaBaseURL;
+ URI repositoryURI = uriInfo.getBaseUri();
+ uri += "?repositoryURL=" + Util.URLencode(repositoryURI.toString());
+ TOSCAComponentId serviceTemplateId = this.getServiceTemplateResource().getId();
+ uri += "&namespace=" + serviceTemplateId.getNamespace().getEncoded();
+ uri += "&id=" + serviceTemplateId.getXmlId().getEncoded();
+ uri += "&plan=" + this.getName();
+ return Response.temporaryRedirect(Utils.createURI(uri)).build();
+ } else {
+ // return Response.ok().entity("No editor plugin found for plan language " + this.o.getPlanLanguage()).build();
+ URI fileURI = uriInfo.getAbsolutePath().resolve("file");
+ return Response.seeOther(fileURI).build();
+ }
+ }
+
+ @Override
+ public String getName() {
+ String name = this.o.getName();
+ if (name == null) {
+ name = this.o.getId();
+ }
+ return name;
+ }
+
+ @Override
+ public Response setName(@FormParam("value") String name) {
+ this.o.setName(name);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("file")
+ public PlanFileResource getPlanFileResource() {
+ return new PlanFileResource((ServiceTemplateResource) this.res, this.getId(), this.o);
+ }
+
+ @GET
+ @Path("type")
+ public String getType() {
+ return this.o.getPlanType();
+ }
+
+ @PUT
+ @Path("type")
+ public Response setType(@FormParam("type") String type) {
+ this.o.setPlanType(type);
+ return BackendUtils.persist(this.res);
+ }
+
+ @GET
+ @Path("language")
+ public String getLanguage() {
+ return this.o.getPlanLanguage();
+ }
+
+ @PUT
+ @Path("language")
+ public Response setLanguage(@FormParam("language") String language) {
+ this.o.setPlanType(language);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("inputparameters/")
+ public ParametersResource getInputParametersResource() {
+ InputParameters inputParameters = this.o.getInputParameters();
+ if (inputParameters == null) {
+ inputParameters = new InputParameters();
+ this.o.setInputParameters(inputParameters);
+ }
+ return new ParametersResource(inputParameters.getInputParameter(), this.getServiceTemplateResource());
+ }
+
+ @Path("outputparameters/")
+ public ParametersResource getOutputParametersResource() {
+ OutputParameters outputParameters = this.o.getOutputParameters();
+ if (outputParameters == null) {
+ outputParameters = new OutputParameters();
+ this.o.setOutputParameters(outputParameters);
+ }
+ return new ParametersResource(outputParameters.getOutputParameter(), this.getServiceTemplateResource());
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java
new file mode 100644
index 0000000..13a8420
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResource.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.plans;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.XMLId;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.common.ids.elements.PlanId;
+import org.eclipse.winery.common.ids.elements.PlansId;
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
+import org.eclipse.winery.repository.Constants;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager;
+import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+/**
+ * Presents the plans nested in one Service Template
+ */
+public class PlansResource extends EntityWithIdCollectionResource<PlanResource, TPlan> {
+
+ private static final Logger logger = LoggerFactory.getLogger(PlansResource.class);
+
+
+ public PlansResource(List<TPlan> plans, ServiceTemplateResource res) {
+ super(PlanResource.class, TPlan.class, plans, res);
+ }
+
+ @Override
+ public Viewable getHTML() {
+ return new Viewable("/jsp/servicetemplates/plans/plans.jsp", new PlansResourceData(this.list));
+ }
+
+ @POST
+ @RestDoc(methodDescription = "<p>Linked plans are currently not supported. Existing plans with the same id are overwritten</p> <p>@return JSON with .tableData: Array with row data for dataTable</p>")
+ @Consumes({MediaType.MULTIPART_FORM_DATA})
+ @Produces(MediaType.APPLICATION_JSON)
+ // the supertype consumes JSON and XML at org.eclipse.winery.repository.resources._support.collections.EntityCollectionResource.addNewElement(EntityT)
+ // @formatter:off
+ public Response onPost(
+ @FormDataParam("planName") String name,
+ @FormDataParam("planType") String type,
+ @FormDataParam("planLanguage") @RestDocParam(description = "the plan language (e..g, BPMN or BPEL). Full URL.") String language,
+ @FormDataParam("file") @RestDocParam(description="(optional in the case of BPMN4TOSCA) file containing the plan.") InputStream uploadedInputStream,
+ @FormDataParam("file") FormDataContentDisposition fileDetail,
+ @FormDataParam("file") FormDataBodyPart body
+ ) {
+ // @formatter:on
+ if (StringUtils.isEmpty(name)) {
+ return Response.status(Status.BAD_REQUEST).entity("planName must be given").build();
+ }
+ if (StringUtils.isEmpty(type)) {
+ return Response.status(Status.BAD_REQUEST).entity("planType must be given").build();
+ }
+ if (StringUtils.isEmpty(language)) {
+ return Response.status(Status.BAD_REQUEST).entity("planLanguage must be given").build();
+ }
+
+ boolean bpmn4toscaMode = org.eclipse.winery.common.constants.Namespaces.URI_BPMN4TOSCA_20.equals(language);
+ if (!bpmn4toscaMode) {
+ if (uploadedInputStream == null) {
+ return Response.status(Status.BAD_REQUEST).entity("file must be given").build();
+ }
+ }
+
+ // A plan carries both a name and an ID
+ // To be user-friendly, we create the ID based on the name
+ // the drawback is, that we do not allow two plans with the same name
+ // during creation, but allow renaming plans to the same name (as we do
+ // not allow ID renaming)
+ String xmlId = Utils.createXMLidAsString(name);
+
+ // BEGIN: Store plan file
+
+ // Determine Id
+ PlansId plansId = new PlansId((ServiceTemplateId) ((ServiceTemplateResource) this.res).getId());
+ PlanId planId = new PlanId(plansId, new XMLId(xmlId, false));
+ // Ensure overwriting
+ if (Repository.INSTANCE.exists(planId)) {
+ try {
+ Repository.INSTANCE.forceDelete(planId);
+ // Quick hack to remove the deleted plan from the plans element
+ ((ServiceTemplateResource) this.res).synchronizeReferences();
+ } catch (IOException e) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+ }
+
+ String fileName;
+ if (bpmn4toscaMode) {
+ fileName = xmlId + Constants.SUFFIX_BPMN4TOSCA;
+ RepositoryFileReference ref = new RepositoryFileReference(planId, fileName);
+ try {
+ Repository.INSTANCE.putContentToFile(ref, "{}", MediaType.APPLICATION_JSON_TYPE);
+ } catch (IOException e1) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not create empty plan. " + e1.getMessage()).build();
+ }
+ } else {
+ // We use the filename also as local file name. Alternatively, we could use the xml id
+ // With URL encoding, this should not be an issue
+ fileName = Util.URLencode(fileDetail.getFileName());
+
+ // Really store it
+ RepositoryFileReference ref = new RepositoryFileReference(planId, fileName);
+ try {
+ Repository.INSTANCE.putContentToFile(ref, uploadedInputStream, body.getMediaType());
+ } catch (IOException e1) {
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity("Could not store plan. " + e1.getMessage()).build();
+ }
+ }
+ // END: Store plan file
+
+ TPlan plan = new TPlan();
+ plan.setId(xmlId);
+ plan.setName(name);
+ plan.setPlanType(type);
+ plan.setPlanLanguage(language);
+ PlansResource.setPlanModelReference(plan, planId, fileName);
+ this.list.add(plan);
+
+ // prepare result
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter sw = new StringWriter();
+ try {
+ JsonGenerator jGenerator = jsonFactory.createGenerator(sw);
+ jGenerator.writeStartObject();
+ jGenerator.writeFieldName("tableData");
+ jGenerator.writeStartArray();
+ jGenerator.writeString(xmlId);
+ jGenerator.writeString(""); // precondition
+ jGenerator.writeString(name);
+ jGenerator.writeString(PlanTypesManager.INSTANCE.getShortName(type));
+ jGenerator.writeString(PlanLanguagesManager.INSTANCE.getShortName(language));
+ jGenerator.writeEndArray();
+ jGenerator.writeEndObject();
+ jGenerator.close();
+ sw.close();
+ } catch (JsonGenerationException e) {
+ PlansResource.logger.error(e.getMessage(), e);
+ return Response.serverError().build();
+ } catch (IOException e) {
+ PlansResource.logger.error(e.getMessage(), e);
+ return Response.serverError().build();
+ }
+
+ Response res = BackendUtils.persist(this.res);
+ if (res.getStatus() == 204) {
+ // everything OK, return created
+ return Response.created(Utils.createURI(Util.URLencode(xmlId))).entity(sw.toString()).build();
+ } else {
+ return res;
+ }
+ }
+
+ static void setPlanModelReference(TPlan plan, PlanId planId, String fileName) {
+ PlanModelReference pref = new PlanModelReference();
+ // Set path relative to Definitions/ path inside CSAR.
+ pref.setReference("../" + Utils.getURLforPathInsideRepo(BackendUtils.getPathInsideRepo(planId)) + fileName);
+ plan.setPlanModelReference(pref);
+ }
+
+ @Override
+ public String getId(TPlan plan) {
+ return plan.getId();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java
new file mode 100644
index 0000000..8527eb4
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/plans/PlansResourceData.java
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.plans;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TPlan;
+import org.eclipse.winery.model.tosca.TPlan.PlanModelReference;
+import org.eclipse.winery.repository.datatypes.TypeWithShortName;
+import org.eclipse.winery.repository.resources.admin.types.PlanLanguagesManager;
+import org.eclipse.winery.repository.resources.admin.types.PlanTypesManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+public class PlansResourceData {
+
+ private static final Logger logger = LoggerFactory.getLogger(PlansResourceData.class);
+
+ // data: [ [id, pre, name, type, lang]* ]
+ private String embeddedPlansTableData;
+
+ // data: [ [id, pre, name, type, lang, reference]* ]
+ private String linkedPlansTableData;
+
+
+ /**
+ * Data object for the JSP
+ *
+ * @param serviceTemplateResource the service template the plans belong to
+ */
+ public PlansResourceData(List<TPlan> plans) {
+ if (plans.isEmpty()) {
+ this.embeddedPlansTableData = "[]";
+ this.linkedPlansTableData = "[]";
+ return;
+ }
+ JsonFactory jsonFactory = new JsonFactory();
+ StringWriter embeddedPlansTableDataSW = new StringWriter();
+ StringWriter linkedPlansTableDataSW = new StringWriter();
+ try {
+ JsonGenerator jGeneratorEmbedded = jsonFactory.createGenerator(embeddedPlansTableDataSW);
+ JsonGenerator jGeneratorLinked = jsonFactory.createGenerator(linkedPlansTableDataSW);
+
+ jGeneratorEmbedded.writeStartArray();
+ jGeneratorLinked.writeStartArray();
+
+ for (TPlan plan : plans) {
+ String name = plan.getName();
+ if (name == null) {
+ // name defaults to id
+ name = plan.getId();
+ }
+ String type = PlanTypesManager.INSTANCE.getShortName(plan.getPlanType());
+ String language = PlanLanguagesManager.INSTANCE.getShortName(plan.getPlanLanguage());
+ PlanModelReference planModelReference = plan.getPlanModelReference();
+ String reference = planModelReference != null ? planModelReference.getReference() : null;
+ JsonGenerator gen;
+ boolean writeReference;
+ if (reference == null) {
+ gen = jGeneratorEmbedded;
+ writeReference = false;
+ } else if (reference.startsWith("../")) {
+ gen = jGeneratorEmbedded;
+ writeReference = false;
+ } else {
+ gen = jGeneratorLinked;
+ writeReference = true;
+ }
+
+ gen.writeStartArray();
+ gen.writeString(plan.getId());
+ gen.writeString(""); // precondition
+ gen.writeString(name);
+ gen.writeString(type);
+ gen.writeString(language);
+ if (writeReference) {
+ gen.writeString(reference);
+ }
+ gen.writeEndArray();
+ }
+
+ jGeneratorEmbedded.writeEndArray();
+ jGeneratorLinked.writeEndArray();
+
+ jGeneratorEmbedded.close();
+ embeddedPlansTableDataSW.close();
+ jGeneratorLinked.close();
+ linkedPlansTableDataSW.close();
+ } catch (JsonGenerationException e) {
+ PlansResourceData.logger.error(e.getMessage(), e);
+ this.embeddedPlansTableData = "[]";
+ this.linkedPlansTableData = "[]";
+ return;
+ } catch (IOException e) {
+ PlansResourceData.logger.error("", e);
+ this.embeddedPlansTableData = "[]";
+ this.linkedPlansTableData = "[]";
+ return;
+ }
+ this.embeddedPlansTableData = embeddedPlansTableDataSW.toString();
+ this.linkedPlansTableData = linkedPlansTableDataSW.toString();
+ }
+
+ public String getEmbeddedPlansTableData() {
+ return this.embeddedPlansTableData;
+ }
+
+ public String getLinkedPlansTableData() {
+ return this.linkedPlansTableData;
+ }
+
+ public Collection<TypeWithShortName> getPlanTypes() {
+ return PlanTypesManager.INSTANCE.getTypes();
+ }
+
+ public Collection<TypeWithShortName> getPlanLanguages() {
+ return PlanLanguagesManager.INSTANCE.getTypes();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java
new file mode 100644
index 0000000..9ce11f9
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionResource.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.eclipse.winery.model.selfservice.ApplicationOption;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OptionResource extends EntityWithIdResource<ApplicationOption> {
+
+ private static final Logger logger = LoggerFactory.getLogger(OptionResource.class);
+
+ static final String ICON_JPG = "icon.jpg";
+ static final String PLAN_INPUT_XML = "plan.input.xml";
+ private SelfServiceMetaDataId ssmdId;
+
+
+ public OptionResource(IIdDetermination<ApplicationOption> idDetermination, ApplicationOption o, int idx, List<ApplicationOption> list, SelfServicePortalResource res) {
+ super(idDetermination, o, idx, list, res);
+ this.ssmdId = ((SelfServicePortalResource) this.res).getId();
+ }
+
+ private String getFileNamePrefix() {
+ return OptionResource.getFileNamePrefix(this.o.getId());
+ }
+
+ public static String getFileNamePrefix(String id) {
+ return "option_" + id + "_";
+ }
+
+ @Path(OptionResource.ICON_JPG)
+ @GET
+ public Response getIcon(@HeaderParam("If-Modified-Since") String modified) {
+ RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.getFileNamePrefix() + OptionResource.ICON_JPG);
+ return BackendUtils.returnRepoPath(ref, modified);
+ }
+
+ @Path("planinputmessage")
+ @GET
+ public Response getPlanInputMessage(@HeaderParam("If-Modified-Since") String modified) {
+ RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.getFileNamePrefix() + OptionResource.PLAN_INPUT_XML);
+ return BackendUtils.returnRepoPath(ref, modified);
+ }
+
+ @Override
+ public Response onDelete() {
+ // delete icon and plan model reference ...
+
+ // delete icon
+ // we use the URL stored in the data instead of the generated URL to be compatible with manually edits
+ RepositoryFileReference ref = new RepositoryFileReference(this.ssmdId, this.o.getIconUrl());
+ try {
+ Repository.INSTANCE.forceDelete(ref);
+ } catch (IOException e) {
+ OptionResource.logger.error("Could not remove file", e);
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+
+ // delete plan input
+ // we use the URL stored in the data instead of the generated URL to be compatible with manually edits
+ ref = new RepositoryFileReference(this.ssmdId, this.o.getPlanInputMessageUrl());
+ try {
+ Repository.INSTANCE.forceDelete(ref);
+ } catch (IOException e) {
+ OptionResource.logger.error("Could not remove file", e);
+ return Response.status(Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
+ }
+
+ // after deleting files, continue with list deletion
+ return super.onDelete();
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java
new file mode 100644
index 0000000..86fa102
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/OptionsResource.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.winery.model.selfservice.ApplicationOption;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId;
+import org.eclipse.winery.repository.resources._support.collections.withid.EntityWithIdCollectionResource;
+import org.restdoc.annotations.RestDoc;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.core.header.FormDataContentDisposition;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+public class OptionsResource extends EntityWithIdCollectionResource<OptionResource, ApplicationOption> {
+
+ private static final Logger logger = LoggerFactory.getLogger(OptionsResource.class);
+
+
+ public OptionsResource(List<ApplicationOption> list, SelfServicePortalResource res) {
+ super(OptionResource.class, ApplicationOption.class, list, res);
+ }
+
+ @Override
+ public String getId(ApplicationOption entity) {
+ return entity.getId();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+ @POST
+ @RestDoc(methodDescription = "Adds a new option<p>TODO: @return JSON with .tableData: Array with row data for dataTable</p>")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ // @formatter:off
+ public Response onPost(
+ @FormDataParam("name") String name,
+ @FormDataParam("description") String description,
+ @FormDataParam("planServiceName") String planServiceName,
+ @FormDataParam("planInputMessage") String planInputMessage,
+ @FormDataParam("file") InputStream uploadedInputStream,
+ @FormDataParam("file") FormDataContentDisposition fileDetail,
+ @FormDataParam("file") FormDataBodyPart body
+ ) {
+ // @formatter:on
+ if (StringUtils.isEmpty(name)) {
+ return Response.status(Status.BAD_REQUEST).entity("planName must be given").build();
+ }
+ if (StringUtils.isEmpty(description)) {
+ return Response.status(Status.BAD_REQUEST).entity("description must be given").build();
+ }
+ if (StringUtils.isEmpty(planServiceName)) {
+ return Response.status(Status.BAD_REQUEST).entity("planServiceName must be given").build();
+ }
+ if (StringUtils.isEmpty(planInputMessage)) {
+ return Response.status(Status.BAD_REQUEST).entity("planInputMessage must be given").build();
+ }
+ if (uploadedInputStream == null) {
+ return Response.status(Status.BAD_REQUEST).entity("file has to be provided").build();
+ }
+ ApplicationOption option = new ApplicationOption();
+
+ String id = Utils.createXMLidAsString(name);
+
+ String fileNamePrefix = OptionResource.getFileNamePrefix(id);
+ String iconFileName = fileNamePrefix + OptionResource.ICON_JPG;
+ String planInputMessageFileName = fileNamePrefix + OptionResource.PLAN_INPUT_XML;
+
+ // create option data
+ option.setId(id);
+ option.setName(name);
+ option.setDescription(description);
+ option.setIconUrl(iconFileName);
+ option.setPlanInputMessageUrl(planInputMessageFileName);
+ option.setPlanServiceName(planServiceName);
+
+ // BEGIN: store icon and planInputMessage
+
+ SelfServiceMetaDataId ssmdId = ((SelfServicePortalResource) this.res).getId();
+
+ RepositoryFileReference iconRef = new RepositoryFileReference(ssmdId, iconFileName);
+ try {
+ Repository.INSTANCE.putContentToFile(iconRef, uploadedInputStream, body.getMediaType());
+ } catch (IOException e) {
+ OptionsResource.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+
+ RepositoryFileReference planInputMessageRef = new RepositoryFileReference(ssmdId, planInputMessageFileName);
+ try {
+ Repository.INSTANCE.putContentToFile(planInputMessageRef, planInputMessage, MediaType.TEXT_XML_TYPE);
+ } catch (IOException e) {
+ OptionsResource.logger.error(e.getMessage(), e);
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+
+ // END: store icon and planInputMessage
+
+ this.list.add(option);
+ Response response = BackendUtils.persist(this.res);
+ return response;
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java
new file mode 100644
index 0000000..98e1dcf
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/selfserviceportal/SelfServicePortalResource.java
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.selfserviceportal;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.taglibs.standard.functions.Functions;
+import org.eclipse.winery.common.RepositoryFileReference;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.model.selfservice.Application;
+import org.eclipse.winery.model.selfservice.Application.Options;
+import org.eclipse.winery.model.tosca.TDocumentation;
+import org.eclipse.winery.repository.JAXBSupport;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.backend.Repository;
+import org.eclipse.winery.repository.datatypes.ids.elements.SelfServiceMetaDataId;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+import com.sun.jersey.multipart.FormDataBodyPart;
+import com.sun.jersey.multipart.FormDataParam;
+
+public class SelfServicePortalResource implements IPersistable {
+
+ private static final Logger logger = LoggerFactory.getLogger(SelfServicePortalResource.class);
+
+ private final ServiceTemplateResource serviceTemplateResource;
+
+ public final RepositoryFileReference data_xml_ref;
+ public final RepositoryFileReference icon_jpg_ref;
+ public final RepositoryFileReference image_jpg_ref;
+
+ private final Application application;
+
+ private final SelfServiceMetaDataId id;
+
+
+ public SelfServicePortalResource(ServiceTemplateId serviceTemplateId) {
+ this(null, serviceTemplateId);
+ }
+
+ public SelfServicePortalResource(ServiceTemplateResource serviceTemplateResource) {
+ this(serviceTemplateResource, (ServiceTemplateId) serviceTemplateResource.getId());
+ }
+
+ SelfServiceMetaDataId getId() {
+ return this.id;
+ }
+
+ /**
+ * @param serviceTemplateResource may be null
+ * @param serviceTemplateId the id, must not be null
+ */
+ private SelfServicePortalResource(ServiceTemplateResource serviceTemplateResource, ServiceTemplateId serviceTemplateId) {
+ this.serviceTemplateResource = serviceTemplateResource;
+ this.id = new SelfServiceMetaDataId(serviceTemplateId);
+ this.data_xml_ref = new RepositoryFileReference(this.id, "data.xml");
+ this.icon_jpg_ref = new RepositoryFileReference(this.id, "icon.jpg");
+ this.image_jpg_ref = new RepositoryFileReference(this.id, "image.jpg");
+ this.application = this.getData();
+ }
+
+ private Application getData() {
+ if (Repository.INSTANCE.exists(this.data_xml_ref)) {
+ Unmarshaller u = JAXBSupport.createUnmarshaller();
+ try (InputStream is = Repository.INSTANCE.newInputStream(this.data_xml_ref);) {
+ return (Application) u.unmarshal(is);
+ } catch (IOException | JAXBException e) {
+ SelfServicePortalResource.logger.error("Could not read from " + this.data_xml_ref, e);
+ return new Application();
+ }
+ } else {
+ return this.getDefaultApplicationData();
+ }
+ }
+
+ private Application getDefaultApplicationData() {
+ Application app = new Application();
+ app.setIconUrl("icon.jpg");
+ app.setImageUrl("image.jpg");
+ if (this.serviceTemplateResource != null) {
+ app.setDisplayName(this.serviceTemplateResource.getName());
+ List<TDocumentation> documentation = this.serviceTemplateResource.getServiceTemplate().getDocumentation();
+ if ((documentation != null) && (!documentation.isEmpty())) {
+ TDocumentation doc = documentation.get(0);
+ List<Object> content = doc.getContent();
+ if ((content != null) && (!content.isEmpty())) {
+ app.setDescription(content.get(0).toString());
+ }
+ }
+ }
+ return app;
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/servicetemplates/selfservicemetadata/selfservicemetadata.jsp", this);
+ }
+
+ @Override
+ public void persist() throws IOException {
+ BackendUtils.persist(this.application, this.data_xml_ref, MediaType.TEXT_XML_TYPE);
+ }
+
+ @PUT
+ @Consumes(MediaType.TEXT_XML)
+ public Response onPutXML(Application data) {
+ String content = Utils.getXMLAsString(data);
+ return BackendUtils.putContentToFile(this.data_xml_ref, content, MediaType.TEXT_XML_TYPE);
+ }
+
+ @Path("icon.jpg")
+ @GET
+ public Response getIcon(@HeaderParam("If-Modified-Since") String modified) {
+ RepositoryFileReference ref = new RepositoryFileReference(this.id, "icon.jpg");
+ return BackendUtils.returnRepoPath(ref, modified);
+ }
+
+ @Path("icon.jpg")
+ @PUT
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response putIcon(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) {
+ RepositoryFileReference ref = new RepositoryFileReference(this.id, "icon.jpg");
+ return BackendUtils.putContentToFile(ref, uploadedInputStream, body.getMediaType());
+ }
+
+ @Path("image.jpg")
+ @GET
+ public Response getImage(@HeaderParam("If-Modified-Since") String modified) {
+ RepositoryFileReference ref = new RepositoryFileReference(this.id, "image.jpg");
+ return BackendUtils.returnRepoPath(ref, modified);
+ }
+
+ @Path("image.jpg")
+ @PUT
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response putImage(@FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataBodyPart body) {
+ RepositoryFileReference ref = new RepositoryFileReference(this.id, "image.jpg");
+ return BackendUtils.putContentToFile(ref, uploadedInputStream, body.getMediaType());
+ }
+
+ @Path("displayname")
+ @PUT
+ public Response onPutOnDisplayName(@FormParam("value") String value) {
+ this.application.setDisplayName(value);
+ return BackendUtils.persist(this);
+ }
+
+ @Path("description")
+ @PUT
+ public Response onPutOnDescription(@FormParam("value") String value) {
+ this.application.setDescription(value);
+ return BackendUtils.persist(this);
+ }
+
+ @Path("options/")
+ public OptionsResource getOptionsResource() {
+ Options options = this.application.getOptions();
+ if (options == null) {
+ options = new Options();
+ this.application.setOptions(options);
+ }
+ return new OptionsResource(options.getOption(), this);
+ }
+
+ /**
+ * @return the internal application object. Used for the export.
+ */
+ public Application getApplication() {
+ return this.application;
+ }
+
+ /**
+ * Used in JSP only
+ */
+ public String getApplicationAsXMLStringEncoded() {
+ String res;
+ if (Repository.INSTANCE.exists(this.data_xml_ref)) {
+ StringWriter sw = new StringWriter();
+ try (InputStream is = Repository.INSTANCE.newInputStream(this.data_xml_ref);) {
+ IOUtils.copy(is, sw);
+ } catch (IOException e) {
+ SelfServicePortalResource.logger.error("Could not read from file", e);
+ }
+ res = sw.toString();
+ } else {
+ // return skeleton for application
+ // application object is already filled with default values if no file exists in repo
+ res = Utils.getXMLAsString(this.getApplication());
+ }
+ return Functions.escapeXml(res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java
new file mode 100644
index 0000000..2a59aa5
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplateResource.java
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.xml.namespace.QName;
+
+import org.eclipse.winery.common.constants.Namespaces;
+import org.eclipse.winery.common.ids.Namespace;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.resources.INodeTemplateResourceOrNodeTypeImplementationResource;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources.artifacts.DeploymentArtifactsResource;
+import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.restdoc.annotations.RestDoc;
+
+public class NodeTemplateResource extends TEntityTemplateResource<TNodeTemplate> implements INodeTemplateResourceOrNodeTypeImplementationResource {
+
+ public NodeTemplateResource(IIdDetermination<TNodeTemplate> idDetermination, TNodeTemplate o, int idx, List<TNodeTemplate> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+
+ @Path("deploymentartifacts/")
+ public DeploymentArtifactsResource getDeploymentArtifacts() {
+ return new DeploymentArtifactsResource(this.o, this);
+ }
+
+ @GET
+ @RestDoc(methodDescription = "* The following methods are currently *not* used by the topology modeler.<br />" + "The modeler is using the repository client to interact with the repository")
+ @Path("minInstances")
+ public String getMinInstances() {
+ return Integer.toString(this.o.getMinInstances());
+ }
+
+ @PUT
+ @Path("minInstances")
+ public Response setMinInstances(@FormParam(value = "minInstances") String minInstances) {
+ int min = Integer.parseInt(minInstances);
+ this.o.setMinInstances(min);
+ return BackendUtils.persist(this.res);
+ }
+
+ @GET
+ @Path("maxInstances")
+ public String getMaxInstances() {
+ return this.o.getMaxInstances();
+ }
+
+ @PUT
+ @Path("maxInstances")
+ public Response setMaxInstances(@FormParam(value = "maxInstances") String maxInstances) {
+ // TODO: check for valid integer | "unbound"
+ this.o.setMaxInstances(maxInstances);
+ return BackendUtils.persist(this.res);
+ }
+
+
+ /* * *
+ * The visual appearance
+ *
+ * We do not use a subresource "visualappearance" here to avoid generation of more objects
+ * * */
+
+ private final QName qnameX = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "x");
+ private final QName qnameY = new QName(Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE, "y");
+
+
+ @Path("x")
+ @GET
+ @RestDoc(methodDescription = "@return the x coordinate of the node template")
+ public String getX() {
+ Map<QName, String> otherAttributes = this.o.getOtherAttributes();
+ return otherAttributes.get(this.qnameX);
+ }
+
+ @Path("x")
+ @PUT
+ public Response setX(String x) {
+ this.o.getOtherAttributes().put(this.qnameX, x);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Path("y")
+ @GET
+ @RestDoc(methodDescription = "@return the y coordinate of the node template")
+ public String getY() {
+ Map<QName, String> otherAttributes = this.o.getOtherAttributes();
+ return otherAttributes.get(this.qnameY);
+ }
+
+ @Path("y")
+ @PUT
+ public Response setY(String y) {
+ this.o.getOtherAttributes().put(this.qnameY, y);
+ return BackendUtils.persist(this.res);
+ }
+
+ @Override
+ public Namespace getNamespace() {
+ // TODO Auto-generated method stub
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+ /**
+ * Required for persistence after a change of the deployment artifact.
+ * Required by DeploymentArtifactResource to be able to persist
+ *
+ * @return the service template this node template belongs to
+ */
+ public ServiceTemplateResource getServiceTemplateResource() {
+ return (ServiceTemplateResource) this.res;
+ }
+
+ /**
+ * required for topology modeler to check for existence of a node template
+ * at the server
+ *
+ * @return empty response
+ */
+ @HEAD
+ public Response getHEAD() {
+ return Response.noContent().build();
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java
new file mode 100644
index 0000000..64c5de8
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/NodeTemplatesResource.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplatesResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class NodeTemplatesResource extends TEntityTemplatesResource<NodeTemplateResource, TNodeTemplate> {
+
+ public NodeTemplatesResource(List<TNodeTemplate> list, IPersistable res) {
+ super(NodeTemplateResource.class, TNodeTemplate.class, list, res);
+ }
+
+ @Override
+ public String getId(TNodeTemplate entity) {
+ return entity.getId();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ // TODO Auto-generated method stub
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java
new file mode 100644
index 0000000..a3eaed5
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplateResource.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources._support.collections.IIdDetermination;
+import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplateResource;
+
+public class RelationshipTemplateResource extends TEntityTemplateResource<TRelationshipTemplate> {
+
+ public RelationshipTemplateResource(IIdDetermination<TRelationshipTemplate> idDetermination, TRelationshipTemplate o, int idx, List<TRelationshipTemplate> list, IPersistable res) {
+ super(idDetermination, o, idx, list, res);
+ }
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java
new file mode 100644
index 0000000..8073e83
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/RelationshipTemplatesResource.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2014 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates;
+
+import java.util.List;
+
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.repository.resources._support.IPersistable;
+import org.eclipse.winery.repository.resources.entitytemplates.TEntityTemplatesResource;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class RelationshipTemplatesResource extends TEntityTemplatesResource<RelationshipTemplateResource, TRelationshipTemplate> {
+
+ public RelationshipTemplatesResource(List<TRelationshipTemplate> list, IPersistable res) {
+ super(RelationshipTemplateResource.class, TRelationshipTemplate.class, list, res);
+ }
+
+ @Override
+ public String getId(TRelationshipTemplate entity) {
+ return entity.getId();
+ }
+
+ @Override
+ public Viewable getHTML() {
+ // TODO Auto-generated method stub
+ throw new IllegalStateException("Not yet implemented.");
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java
new file mode 100644
index 0000000..b4b3646
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/servicetemplates/topologytemplates/TopologyTemplateResource.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2015 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.servicetemplates.topologytemplates;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.eclipse.winery.common.Util;
+import org.eclipse.winery.common.ids.definitions.ServiceTemplateId;
+import org.eclipse.winery.model.tosca.TEntityTemplate;
+import org.eclipse.winery.model.tosca.TNodeTemplate;
+import org.eclipse.winery.model.tosca.TRelationshipTemplate;
+import org.eclipse.winery.model.tosca.TTopologyTemplate;
+import org.eclipse.winery.repository.Prefs;
+import org.eclipse.winery.repository.Utils;
+import org.eclipse.winery.repository.backend.BackendUtils;
+import org.eclipse.winery.repository.client.IWineryRepositoryClient;
+import org.eclipse.winery.repository.client.WineryRepositoryClientFactory;
+import org.eclipse.winery.repository.json.TopologyTemplateModule;
+import org.eclipse.winery.repository.resources.servicetemplates.ServiceTemplateResource;
+import org.restdoc.annotations.RestDoc;
+import org.restdoc.annotations.RestDocParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.WebResource.Builder;
+import com.sun.jersey.api.view.Viewable;
+
+public class TopologyTemplateResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(TopologyTemplateResource.class);
+
+ private final TTopologyTemplate topologyTemplate;
+
+ private final ServiceTemplateResource serviceTemplateRes;
+
+
+ /**
+ * A topology template is always nested in a service template
+ */
+ public TopologyTemplateResource(ServiceTemplateResource parent) {
+ this.topologyTemplate = parent.getServiceTemplate().getTopologyTemplate();
+ this.serviceTemplateRes = parent;
+ }
+
+
+ public static class DataForJSP {
+
+ private String location;
+ private TTopologyTemplate topologyTemplate;
+ private URI repositoryURI;
+ private String additonalCSS;
+ private Boolean autoLayoutOnLoad;
+ private String additionalScript;
+
+
+ public DataForJSP(String location, URI repositoryURI, TTopologyTemplate topologyTemplate, String additonalCSS, String additionalScript, Boolean autoLayoutOnLoad) {
+ this.location = location;
+ this.repositoryURI = repositoryURI;
+ this.topologyTemplate = topologyTemplate;
+ this.additonalCSS = additonalCSS;
+ this.additionalScript = additionalScript;
+ this.autoLayoutOnLoad = autoLayoutOnLoad;
+ }
+
+ public String getLocation() {
+ return this.location;
+ }
+
+ public TTopologyTemplate getTopologyTemplate() {
+ return this.topologyTemplate;
+ }
+
+ public String getAdditonalCSS() {
+ return this.additonalCSS;
+ }
+
+ public String getAdditionalScript() {
+ return this.additionalScript;
+ }
+
+ public Boolean getAutoLayoutOnLoad() {
+ return this.autoLayoutOnLoad;
+ }
+
+ public IWineryRepositoryClient getClient() {
+ // Quick hack
+ // IWineryRepository is not implemented by Prefs.INSTANCE.getRepository()
+ // Therefore, we have to generate a real WineryRepositoryClient even if that causes more http load
+ IWineryRepositoryClient client = WineryRepositoryClientFactory.getWineryRepositoryClient();
+ client.addRepository(this.repositoryURI.toString());
+ return client;
+ }
+
+ }
+
+
+ @GET
+ @RestDoc(methodDescription = "?edit is used in the URL to get the jsPlumb-based editor")
+ @Produces(MediaType.TEXT_HTML)
+ // @formatter:off
+ public Response getHTML(
+ @QueryParam(value = "edit") String edit,
+ @QueryParam(value = "script") @RestDocParam(description = "the script to include in a <script> tag. The function wineryViewExternalScriptOnLoad if it is defined. Only available if 'view' is also set") String script,
+ @QueryParam(value = "view") String view,
+ @QueryParam(value = "autoLayoutOnLoad") String autoLayoutOnLoad,
+ @Context UriInfo uriInfo) {
+ // @formatter:on
+ Response res;
+ String JSPName;
+ String location = Prefs.INSTANCE.getWineryTopologyModelerPath();
+ location = uriInfo.getBaseUri().resolve(location).toString();
+ // at the topology modeler, jersey needs to have an absolute path
+ URI repositoryURI = uriInfo.getBaseUri();
+ location = location + "/?repositoryURL=";
+ location = location + Util.URLencode(repositoryURI.toString());
+ ServiceTemplateId serviceTemplate = (ServiceTemplateId) this.serviceTemplateRes.getId();
+ location = location + "&ns=";
+ location = location + serviceTemplate.getNamespace().getEncoded();
+ location = location + "&id=";
+ location = location + serviceTemplate.getXmlId().getEncoded();
+ if (edit == null) {
+ String additionalCSS = null;
+ Boolean autoLayoutOnLoadBoolean = false;
+ if (view == null) {
+ // integration in Winery
+ // currently not maintained: Winery includes ?view as iframe
+ JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplate.jsp";
+ } else {
+ // view only mode
+ // fullscreen: additionalCSS and script possible
+ if (!"".equals(view)) {
+ // view with additional CSS
+ URI cssURI = URI.create(view);
+ if (cssURI.isAbsolute()) {
+ additionalCSS = view;
+ } else {
+ // relative URLs starts at "/css/topologyrendering/"
+ additionalCSS = uriInfo.getBaseUri().resolve("css/topologytemplaterendering/").resolve(view).toString();
+ if (!additionalCSS.endsWith(".css")) {
+ additionalCSS += ".css";
+ }
+ }
+ }
+ if (autoLayoutOnLoad != null) {
+ autoLayoutOnLoadBoolean = true;
+ }
+ JSPName = "/jsp/servicetemplates/topologytemplates/topologytemplateview.jsp";
+ }
+ Viewable viewable = new Viewable(JSPName, new DataForJSP(location, repositoryURI, this.topologyTemplate, additionalCSS, script, autoLayoutOnLoadBoolean));
+ res = Response.ok().header(HttpHeaders.VARY, HttpHeaders.ACCEPT).entity(viewable).build();
+ } else {
+ // edit mode
+ URI uri = Utils.createURI(location);
+ res = Response.seeOther(uri).build();
+ }
+ return res;
+ }
+
+ /**
+ *
+ * @param uriInfo the URI ending with "topologytemplate/" of a service
+ * template
+ */
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response triggerGenerateBuildPlan(@Context UriInfo uriInfo) {
+ String plansURI = uriInfo.getAbsolutePath().resolve("../plans/").toString();
+ String csarURI = uriInfo.getAbsolutePath().resolve("../?csar").toString();
+
+ String request = "<generatePlanForTopology><CSARURL>";
+ request += csarURI;
+ request += "</CSARURL><PLANPOSTURL>";
+ request += plansURI;
+ request += "</PLANPOSTURL></generatePlanForTopology>";
+
+ Client client = Client.create();
+ Builder wr = client.resource("http://localhost:1339/planbuilder/sync").type(MediaType.APPLICATION_XML);
+
+ try {
+ wr.post(String.class, request);
+ } catch (com.sun.jersey.api.client.UniformInterfaceException e) {
+ return Response.serverError().entity(e.getMessage()).build();
+ }
+
+ return Response.ok().build();
+ }
+
+ // @formatter:off
+ @GET
+ @RestDoc(methodDescription="Returns a JSON representation of the topology template. <br />" +
+ "X and Y coordinates are embedded as attributes. QName string with Namespace: <br />" +
+ "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} <br />" +
+ "@return The JSON representation of the topology template <em>without</em> associated artifacts and without the parent service template")
+ @Produces(MediaType.APPLICATION_JSON)
+ // @formatter:on
+ public Response getComponentInstanceJSON() {
+ Response res;
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.enable(SerializationFeature.INDENT_OUTPUT);
+ mapper.registerModule(new TopologyTemplateModule());
+ try {
+ // convert it to json
+ String json = mapper.writeValueAsString(this.topologyTemplate);
+ res = Response.ok(json).build();
+ } catch (Exception e) {
+ TopologyTemplateResource.logger.error(e.getMessage(), e);
+ res = Response.serverError().entity(e.getMessage()).build();
+ }
+ return res;
+ }
+
+ @Path("nodetemplates/")
+ public NodeTemplatesResource getNodeTemplatesResource() {
+ // FIXME: onDelete will not work as we have a copy of the original list. We have to add a "listener" to remove at the list and route that remove to the original list
+ List<TNodeTemplate> l = BackendUtils.getAllNestedNodeTemplates(this.serviceTemplateRes.getServiceTemplate());
+ return new NodeTemplatesResource(l, this.serviceTemplateRes);
+ }
+
+ @Path("relationshiptemplates/")
+ public RelationshipTemplatesResource getRelationshipTemplatesResource() {
+ // FIXME: onDelete will not work. See getNodeTemplatesResource
+ List<TRelationshipTemplate> l = new ArrayList<TRelationshipTemplate>();
+ for (TEntityTemplate t : this.topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
+ if (t instanceof TRelationshipTemplate) {
+ l.add((TRelationshipTemplate) t);
+ }
+ }
+ return new RelationshipTemplatesResource(l, this.serviceTemplateRes);
+ }
+
+ @PUT
+ @RestDoc(methodDescription = "Replaces the topology by the information given in the XML")
+ @Consumes(MediaType.TEXT_XML)
+ public Response setModel(TTopologyTemplate topologyTemplate) {
+ this.serviceTemplateRes.getServiceTemplate().setTopologyTemplate(topologyTemplate);
+ return BackendUtils.persist(this.serviceTemplateRes);
+ }
+
+ // @formatter:off
+ @GET
+ @RestDoc(methodDescription="<p>Returns an XML representation of the topology template." +
+ " X and Y coordinates are embedded as attributes. Namespace:" +
+ "{@link org.eclipse.winery.repository.common.constants.Namespaces.TOSCA_WINERY_EXTENSIONS_NAMESPACE} </p>" +
+ "<p>{@link org.eclipse.winery.repository.client.WineryRepositoryClient." +
+ "getTopologyTemplate(QName)} consumes this template</p>" +
+ "<p>@return The XML representation of the topology template <em>without</em>" +
+ "associated artifacts and without the parent service template </p>")
+ @Produces(MediaType.TEXT_XML)
+ // @formatter:on
+ public Response getComponentInstanceXML() {
+ return Utils.getXML(TTopologyTemplate.class, this.topologyTemplate);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java
new file mode 100644
index 0000000..21596e6
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/resources/tags/TagsResource.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012-2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.resources.tags;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import org.eclipse.winery.common.ids.definitions.TOSCAComponentId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.sun.jersey.api.view.Viewable;
+
+public class TagsResource {
+
+ private static final Logger logger = LoggerFactory.getLogger(TagsResource.class);
+
+
+ public TagsResource(TOSCAComponentId parentId) {
+ }
+
+ @GET
+ @Produces(MediaType.TEXT_HTML)
+ public Viewable getHTML() {
+ return new Viewable("/jsp/tags/tags.jsp", this);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java
new file mode 100644
index 0000000..2c97e64
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/OpenTOSCAContainerConnection.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.winery.repository.runtimeintegration;
+
+import org.eclipse.winery.repository.Utils;
+
+public class OpenTOSCAContainerConnection {
+
+ /**
+ * Determines whether the OpenTOSCA container is locally available
+ *
+ * We currently check for localhost only as Winery currently does not allow
+ * for configuring an URL for the container
+ */
+ public static boolean isContainerLocallyAvailable() {
+ // the string determining the location of the OpenTOSCA container admin resource
+ String adminPath = "http://localhost:8080/admin/";
+ return Utils.isResourceAvailable(adminPath);
+ }
+
+}
diff --git a/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java
new file mode 100644
index 0000000..9627605
--- /dev/null
+++ b/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/runtimeintegration/package-info.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2013 University of Stuttgart.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and the Apache License 2.0 which both accompany this distribution,
+ * and are available at http://www.eclipse.org/legal/epl-v10.html
+ * and http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Contributors:
+ * Oliver Kopp - initial API and implementation
+ *******************************************************************************/
+
+/**
+ * This package offers classees to integrate different TOSCA runtimes
+ */
+package org.eclipse.winery.repository.runtimeintegration; \ No newline at end of file