Core Data Services (CDS) which serves as a standard modelling language for both domain models and service descriptions. Service SDKs and runtimes for Java and Node.js. They provide frameworks for creating and using services and generic provider implementations that can automatically handle many requests.
mkdir sdmapps sdmapps/java
git clone -b java https://github.com/alphageek7443/sdmapps
cd sdmapps/java/sdm-service
mvn -B archetype:generate \
-DarchetypeArtifactId=cds-services-archetype \
-DarchetypeGroupId=com.sap.cds \
-DarchetypeVersion=RELEASE \
-DgroupId=com.sap.cap -DartifactId=sdm-service
cd sdm-service
code .
namespace sap.capire.media;
entity Pictures {
key ID : UUID;
name : String;
repositoryId : String;
content : LargeBinary @Core.MediaType: mediaType;
mediaType : String @Core.IsMediaType : true;
}
using { sap.capire.media as db } from '../db/schema';
service DocumentService{
entity Pictures as projection on db.Pictures;
}
mvn clean install
package com.sap.cap.sdmservice.handlers;
import org.springframework.stereotype.Component;
import com.sap.cds.services.cds.CdsReadEventContext;
import com.sap.cds.services.cds.CdsService;
import com.sap.cds.services.cds.CdsUpdateEventContext;
import com.sap.cds.services.handler.EventHandler;
import com.sap.cds.services.handler.annotations.On;
import com.sap.cds.services.handler.annotations.ServiceName;
import cds.gen.documentservice.DocumentService_;
import cds.gen.documentservice.Pictures;
import cds.gen.documentservice.Pictures_;
@Component
@ServiceName(DocumentService_.CDS_NAME)
public class DocumentService implements EventHandler {
@On(event = CdsService.EVENT_READ, entity = Pictures_.CDS_NAME)
public void read(CdsReadEventContext context){
System.out.println(this.getClass().getSimpleName()+": "
+context.getEvent());
}
@On(event = CdsService.EVENT_UPDATE, entity = Pictures_.CDS_NAME)
public void update(CdsUpdateEventContext context, Pictures pictures) {
System.out.println(this.getClass().getSimpleName()+": "
+context.getEvent());
}
}
<dependency>
<groupId>com.sap.cds</groupId>
<artifactId>cds-starter-cloudfoundry</artifactId>
</dependency>
<dependency>
<groupId>org.apache.chemistry.opencmis</groupId>
<artifactId>chemistry-opencmis-client-impl</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.sap.cloud.security.xsuaa</groupId>
<artifactId>token-client</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
package com.sap.cap.sdmservice.model;
import java.util.LinkedHashMap;
import java.util.Map;
import com.sap.cloud.security.config.CredentialType;
import com.sap.cloud.security.xsuaa.XsuaaCredentials;
public class SDMUaa {
private final String uri;
private final XsuaaCredentials credentials;
public SDMUaa(Map<String, Object> credentials){
@SuppressWarnings (value="unchecked")
Map<String, String> uaa = (LinkedHashMap<String, String>)
credentials.get("uaa");
this.uri =(String) credentials.get("uri");
this.credentials = new XsuaaCredentials();
this.credentials.setClientId(uaa.get("clientid"));
this.credentials.setClientSecret(uaa.get("clientsecret"));
this.credentials.setUrl(uaa.get("url"));
this.credentials.setCredentialType(CredentialType
.from(uaa.get("credential-type")));
}
public String getUri() {
return this.uri;
}
public XsuaaCredentials getCredentials() {
return this.credentials;
}
}
package com.sap.cap.sdmservice.config;
import java.util.HashMap;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.api.SessionFactory;
import org.apache.chemistry.opencmis.client.runtime.SessionFactoryImpl;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.apache.chemistry.opencmis.commons.enums.BindingType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.sap.cds.services.EventContext;
import com.sap.cds.services.authentication.JwtTokenAuthenticationInfo;
@Component
public class ConnectSDMDataSource {
private HashMap<String, String> parameters;
private SDMDataSource sdmDataSource;
@Autowired
public ConnectSDMDataSource(SDMDataSource sdmDataSource){
this.sdmDataSource = sdmDataSource;
this.parameters = new HashMap<String, String>();
parameters.put(SessionParameter.BINDING_TYPE,
BindingType.BROWSER.value());
parameters.put(SessionParameter.AUTH_HTTP_BASIC, "false");
parameters.put(SessionParameter.AUTH_SOAP_USERNAMETOKEN, "false");
parameters.put(SessionParameter.AUTH_OAUTH_BEARER, "true");
}
public ConnectSDMDataSource setParameter(String parameter, String value){
this.parameters.put(parameter, value);
return this;
}
public Session getSession(EventContext context,String repositoryId){
JwtTokenAuthenticationInfo jwtTokenAuthenticationInfo =
context.getAuthenticationInfo().as(JwtTokenAuthenticationInfo.class);
String token = sdmDataSource.getUserAccessToken(
jwtTokenAuthenticationInfo.getToken()).get();
this.setParameter(SessionParameter.BROWSER_URL,
sdmDataSource.getBrowerUrl())
.setParameter(SessionParameter.OAUTH_ACCESS_TOKEN, token)
.setParameter(SessionParameter.REPOSITORY_ID, repositoryId);
SessionFactory factory = SessionFactoryImpl.newInstance();
return factory.createSession(parameters);
}
}
package com.sap.cap.sdmservice.config;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.sap.cap.sdmservice.model.SDMUaa;
import com.sap.cds.services.runtime.CdsRuntime;
import com.sap.cloud.security.client.HttpClientFactory;
import com.sap.cloud.security.config.OAuth2ServiceConfiguration;
import com.sap.cloud.security.config.OAuth2ServiceConfigurationBuilder;
import com.sap.cloud.security.config.Service;
import com.sap.cloud.security.xsuaa.client.DefaultOAuth2TokenService;
import com.sap.cloud.security.xsuaa.client.OAuth2TokenResponse;
import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints;
import com.sap.cloud.security.xsuaa.tokenflows.TokenFlowException;
import com.sap.cloud.security.xsuaa.tokenflows.UserTokenFlow;
import com.sap.cloud.security.xsuaa.tokenflows.XsuaaTokenFlows;
@Component
public class SDMDataSource {
private CdsRuntime cdsRuntime;
private SDMUaa sdmUaa;
private UserTokenFlow userTokenFlow;
@Autowired
public SDMDataSource(CdsRuntime cdsRuntime){
this.cdsRuntime = cdsRuntime;
createDataSource();
setUserTokenFlow();
}
public Optional<String> getUserAccessToken(String token) {
OAuth2TokenResponse oAuth2TokenResponse = null;
try {
oAuth2TokenResponse = this.userTokenFlow
.token(token).execute();
} catch (TokenFlowException ex) {
ex.printStackTrace();
}
return Optional.ofNullable(oAuth2TokenResponse.getAccessToken());
}
public String getBrowerUrl(){
return this.sdmUaa.getUri()+"browser";
}
private void createDataSource() {
List<SDMUaa> sdmUaas = cdsRuntime.getEnvironment()
.getServiceBindings()
.filter(b -> b.matches("sdm", "sdm"))
.map(b -> new SDMUaa(b.getCredentials()))
.collect(Collectors.toList());
this.sdmUaa = sdmUaas.stream().findFirst().orElse(null);
}
private void setUserTokenFlow(){
OAuth2ServiceConfigurationBuilder builder =
OAuth2ServiceConfigurationBuilder.forService(Service.XSUAA);
OAuth2ServiceConfiguration config = builder
.withClientId(sdmUaa.getCredentials().getClientId())
.withClientSecret(sdmUaa.getCredentials().getClientSecret())
.withPrivateKey(sdmUaa.getCredentials().getKey())
.withUrl(sdmUaa.getCredentials().getUrl())
.build();
XsuaaTokenFlows xsuaaTokenFlows = new XsuaaTokenFlows(
new DefaultOAuth2TokenService(HttpClientFactory
.create(config.getClientIdentity())),
new XsuaaDefaultEndpoints(config),
config.getClientIdentity());
this.userTokenFlow= xsuaaTokenFlows.userTokenFlow();
}
}
@Autowired
private ConnectSDMDataSource connectSDMDataSource;
@Autowired
private PersistenceService db;
private final CqnAnalyzer analyzer;
@Autowired
DocumentService(CdsModel model) {
this.analyzer = CqnAnalyzer.create(model);
}
private Session getCMISSession(
EventContext context, String repositoryId) {
return connectSDMDataSource.getSession(context, repositoryId);
}
@On(event = CdsService.EVENT_UPDATE, entity = Pictures_.CDS_NAME)
public void update(CdsUpdateEventContext context, Pictures pictures) {
Result result = db.run(Select.from(Pictures_.CDS_NAME)
.byId(pictures.getId()));
Pictures picture = result.listOf(Pictures.class).get(0);
String repositoryId = result.first().get()
.get(Pictures.REPOSITORY_ID).toString();
String fileExtension= MimeTypeUtils.parseMimeType
(pictures.getMediaType().toString()).getSubtype();
String fileName = result.first().get().get(Pictures.ID)
.toString()+"."+fileExtension;
Session session = this.getCMISSession(context, repositoryId);
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PropertyIds.OBJECT_TYPE_ID, "cmis:document");
properties.put(PropertyIds.NAME, fileName);
try {
ContentStream contentStream = ContentStreamUtils
.createByteArrayContentStream(
fileName, IOUtils.toByteArray( pictures.getContent()),
pictures.getMediaType());
Folder folder = session.getRootFolder();
Document document = folder.createDocument(properties,
contentStream, VersioningState.MAJOR);
System.out.println(document.getContentUrl());
} catch (IOException e) {
e.printStackTrace();
}
picture.setMediaType(pictures.getMediaType().toString());
context.setResult(Arrays.asList(picture));
context.setCompleted();
}
@On(event = CdsService.EVENT_READ, entity = Pictures_.CDS_NAME)
public void read(CdsReadEventContext context){
AnalysisResult analysisResult = analyzer
.analyze(context.getCqn().ref());
Object id = analysisResult.rootKeys().get("ID");
ArrayList<ResolvedRefItem> resolvedRefItems =
(ArrayList<ResolvedRefItem>) analyzer
.resolveRefItems(context.getCqn());
if (id != null && resolvedRefItems.size() == 2
&& resolvedRefItems.get(0)
.displayName().equals("content")) {
Result resultQuery = db.run(Select.from(DocumentService_.PICTURES)
.where(picture -> picture.ID().eq(id.toString())));
Pictures picture = resultQuery.listOf(Pictures.class).get(0);
Session session = getCMISSession(context, picture.getRepositoryId());
String filename = picture.getId().toString();
ItemIterable <QueryResult> cmisResults =session.query(
"SELECT cmis:objectId FROM cmis:document where cmis:name LIKE "+
"'"+filename+"%'",
false);
String objectId = null;
for(QueryResult hit: cmisResults) {
for(PropertyData<?> property: hit.getProperties()) {
if(property.getQueryName().equals("cmis:objectId")){
objectId = property.getFirstValue().toString();
break;
}
}
}
Document document = session.getLatestDocumentVersion(objectId);
picture.setContent(document.getContentStream().getStream());
picture.setMediaType(document.getContentStreamMimeType());
context.setResult(Arrays.asList(picture));
}
}
Add the following import statements to the top of the DocumentService.java class and make sure you Save the file:
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.chemistry.opencmis.client.api.Document;
import org.apache.chemistry.opencmis.client.api.Folder;
import org.apache.chemistry.opencmis.client.api.ItemIterable;
import org.apache.chemistry.opencmis.client.api.QueryResult;
import org.apache.chemistry.opencmis.client.api.Session;
import org.apache.chemistry.opencmis.client.util.ContentStreamUtils;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.MimeTypeUtils;
import com.sap.cap.sdmservice.config.ConnectSDMDataSource;
import com.sap.cds.Result;
import com.sap.cds.ql.Select;
import com.sap.cds.ql.cqn.AnalysisResult;
import com.sap.cds.ql.cqn.CqnAnalyzer;
import com.sap.cds.ql.cqn.ResolvedRefItem;
import com.sap.cds.reflect.CdsModel;
import com.sap.cds.services.EventContext;
import com.sap.cds.services.cds.CdsReadEventContext;
import com.sap.cds.services.cds.CdsService;
import com.sap.cds.services.cds.CdsUpdateEventContext;
import com.sap.cds.services.handler.EventHandler;
import com.sap.cds.services.handler.annotations.On;
import com.sap.cds.services.handler.annotations.ServiceName;
import com.sap.cds.services.persistence.PersistenceService;
import cds.gen.documentservice.DocumentService_;
import cds.gen.documentservice.Pictures;
import cds.gen.documentservice.Pictures_;
{
...
"devDependencies": {
...
},
"engines": {
"node": "^16"
},
cds add mta
...
requires:
- name: sdmsrv
- name: sdmxsuaa
resources:
- name: sdmxsuaa
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json
- name: sdmsrv
type: org.cloudfoundry.managed-service
parameters:
service: sdm
service-plan: free
{
"xsappname": "sdmxsuaa",
"tenant-mode": "dedicated",
"description": "Security profile for SDM Application ",
"scopes": [
{
"name": "uaa.user",
"description": "UAA"
}
],
"role-templates": [
{
"name": "Token_Exchange",
"description": "UAA",
"scope-references": [
"uaa.user"
]
}
]
}
mbt build -t ./
cf deploy sdm-service_1.0.0-SNAPSHOT.mtar
cf apps
cf env sdm-service-srv \
| sed -n '/VCAP_SERVICES/,/VCAP_APPLICATION/p' \
| sed '$d' \
| sed '1s;^;{\n;' \
| sed '$s/$/}/' \
| sed '/^{}$/d' > default-env.json
POST https://{{application URL}}/odata/v4/DocumentService/Pictures
Authorization: Bearer {{token}}
Content-Type: application/json
{
"name":"SAP BTP image",
"repositoryId": "7cac5ffa-63f7-43f9-8b20-52d78f494f09"
}
PUT https://{{application URL}}/odata/v4/DocumentService/Pictures/{{id}}/content
Authorization: Bearer {{token}}
Content-Type: image/png
<MEDIA>
GET https://{{application URL}}/odata/v4/DocumentService/Pictures/{{id}}/content
Authorization: Bearer {{token}}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
17 | |
11 | |
7 | |
7 | |
7 | |
7 | |
6 | |
6 | |
6 | |
6 |