OData 4.0 Services (CRUD) using Olingo(JSON supported): Part-1
1) Import the following jars for OLINGO
odata-commons-api-4.0.0.jar
odata-commons-core-4.0.0.jar
odata-server-core-4.0.0.jar
slf4j-api-1.7.11.jar
commons-codec-1.9.jar
slf4j-simple-1.7.7.jar
jackson-dataformat-xml-2.4.2.jar
jackson-databind-2.4.2.jar
odata-server-api-4.0.0.jar
jackson-annotations-2.4.2.jar
antlr4-runtime-4.5.jar
stax2-api-3.1.4.jar
org.abego.treelayout.core-1.0.1.jar
jackson-module-jaxb-annotations-2.4.2.jar
commons.lang3-3.3.2.jar
jackson-core-2.4.2.jar
aalto-xml-0.9.10.jar
2) Create Provider that extends CsdlAbstractEdmProvider
- 1.Define Namespace, Container, EntityType names, EntitySet names.
- a. DEFINING NAMESPACE :
public static final String NAMESPACE = “OData.Demo”;
- b. DEFINING CONTAINER :
public static final String CONTAINER_NAME = “Container”;
public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
- c. DEFINING ENTITY TYPE NAMES :
public static final String ET_STUDENT_NAME = “Student”;
public static final FullQualifiedName ET_STUDENT_FQN = new FullQualifiedName (NAMESPACE, ET_STUDENT_NAME);
public static final String ET_SCHOOL_NAME = “School”;
public static final FullQualifiedName ET_SCHOOL_FQN =FullQualifiedName(NAMESPACE, ET_SCHOOL_NAME);
- d. DEFINING ENTITY SETS :
public static final String ES_STUDENTS_NAME = “Students”;
public static final String ES_SCHOOLS_NAME = “Schools”;
- e. DEFINING NAVIGATIONS:
public static final String NAV_TO_SCHOOL = “School”;
public static final String NAV_TO_STUDENTS = “Students”;
- 2. Override getEntityType, getEntitySet, getEntityContainerInfo, getEntityContainer, getSchemas methods .
- a. OVERRIDING getEntityType:
@Override
public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) {
// this method is called for each EntityType that are configured in the Schema
CsdlEntityType entityType = null;
if (entityTypeName.equals(ET_STUDENT_FQN)) {
// create EntityType properties
CsdlProperty stu_id = new CsdlProperty().setName(“stu_id”)
.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
CsdlProperty stu_name = new CsdlProperty().setName(“stu_name”)
.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
// create PropertyRef for Key element
CsdlPropertyRef propertyRef = new CsdlPropertyRef();
propertyRef.setName(“stu_id”);
// navigation property: many-to-one, null not allowed (student must have a school)
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName(NAV_TO_SCHOOL)
.setType(ET_SCHOOL_FQN).setNullable(false).setPartner(“Students”);
//add all the navigation properties to a list
List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
navPropList.add(navProp);
// configure EntityType
entityType = new CsdlEntityType();
entityType.setName(ET_STUDENT_NAME);
entityType.setProperties(Arrays.asList(stu_id, stu_name));
entityType.setKey(Arrays.asList(propertyRef));
entityType.setNavigationProperties(navPropList);
} else if (entityTypeName.equals(ET_SCHOOL_FQN)) {
// create EntityType properties
CsdlProperty school_id = new CsdlProperty().setName(“school_id”)
.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
CsdlProperty school_name = new CsdlProperty().setName(“school_name”)
.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
// create PropertyRef for Key element
CsdlPropertyRef propertyRef = new CsdlPropertyRef();
propertyRef.setName(“school_name”);
// navigation property: one-to-many(a school can have many students)
CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName(NAV_TO_STUDENTS)
.setType(ET_STUDENT_FQN).setCollection(true).setPartner(“School”);
\
//add all navigation properties to a list
List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
navPropList.add(navProp);
// configure EntityType
entityType = new CsdlEntityType();
entityType.setName(ET_SCHOOL_NAME);
entityType.setProperties(Arrays.asList(school_id, school_name));
entityType.setKey(Arrays.asList(propertyRef));
entityType.setNavigationProperties(navPropList);
}
return entityType;
}
- b. OVERRIDING getEntitySets:
@Override
public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) {
CsdlEntitySet entitySet = null;
if (entityContainer.equals(CONTAINER)) {
if (entitySetName.equals(ES_STUDENTS_NAME)) {
entitySet = new CsdlEntitySet();
entitySet.setName(ES_STUDENTS_NAME);
entitySet.setType(ET_STUDENT_FQN);
// navigation
CsdlNavigationPropertyBinding navPropBinding = new CsdlNavigationPropertyBinding();
navPropBinding.setTarget(“Schools”); // the target entity set, where the navigation property points to
navPropBinding.setPath(“School”); // the path from entity type to navigation property
//add all navigation property bindings to a list
List<CsdlNavigationPropertyBinding> navPropBindingList = new ArrayList<CsdlNavigationPropertyBinding>();
navPropBindingList.add(navPropBinding);
entitySet.setNavigationPropertyBindings(navPropBindingList);
} else if (entitySetName.equals(ES_SCHOOLS_NAME)) {
entitySet = new CsdlEntitySet();
entitySet.setName(ES_SCHOOLS_NAME);
entitySet.setType(ET_SCHOOL_FQN);
// navigation
CsdlNavigationPropertyBinding navPropBinding = new CsdlNavigationPropertyBinding();
navPropBinding.setTarget(“Students”); // the target entity set, where the navigation property points to
navPropBinding.setPath(“Students”); // the path from entity type to navigation property
//add all navigation property bindings to a list
List<CsdlNavigationPropertyBinding> navPropBindingList = new ArrayList<CsdlNavigationPropertyBinding>();
navPropBindingList.add(navPropBinding);
entitySet.setNavigationPropertyBindings(navPropBindingList);
}
}
return entitySet;
}
- c. OVERRIDING getEntityContainerInfo
@Override
public CsdlEntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) {
// This method is invoked when displaying the service document at
// eg: http://localhost:8088/school_stu_teachers/DemoService.svc/
if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
entityContainerInfo.setContainerName(CONTAINER);
return entityContainerInfo;
}
return null;
}
- d. OVERRIDING getSchemas
@Override
public List<CsdlSchema> getSchemas() {
// create Schema and set the namespace to schema
CsdlSchema schema = new CsdlSchema();
schema.setNamespace(NAMESPACE);
// add EntityTypes
List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
entityTypes.add(getEntityType(ET_STUDENT_FQN));
entityTypes.add(getEntityType(ET_SCHOOL_FQN));
schema.setEntityTypes(entityTypes);
// add EntityContainer
schema.setEntityContainer(getEntityContainer());
// finally add current schema to the list of schemas
List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
schemas.add(schema);
return schemas;
}
- e. DEFINING getEntityContainer
@Override
public CsdlEntityContainer getEntityContainer() {
// create EntitySets
List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
entitySets.add(getEntitySet(CONTAINER, ES_STUDENTS_NAME));
entitySets.add(getEntitySet(CONTAINER, ES_SCHOOLS_NAME));
// create EntityContainer
CsdlEntityContainer entityContainer = new CsdlEntityContainer();
entityContainer.setName(CONTAINER_NAME);
entityContainer.setEntitySets(entitySets);
return entityContainer;
}
}
Metadata:
3)Create processor (for Entity) that implements Entityprocessor:
- a. Create readEntity method that gets called on ‘GET’ request
/**
* This method is invoked when a single entity has to be read. In our
* example, this can be either a “normal” read operation, or a navigation:
*
* Example for “normal” read operation:
* http://localhost:8080/school_stu_teachers/DemoService.svc/Students(1)
*
* Example for navigation
* http://localhost:8080/school_stu_teachers/DemoService.svc/Students(1)/School
*/
public void readEntity(ODataRequest request, ODataResponse response,UriInfo uriInfo, ContentType responseFormat)throws ODataApplicationException, SerializerException {
EdmEntityType responseEdmEntityType = null; // we’ll need this to build
//the ContextURL
Entity responseEntity = new Entity(); // required for serialization of the response body
EdmEntitySet responseEdmEntitySet = null; // we need this for building
// 1st step: retrieve the requested Entity: can be “normal” read
// operation, or navigation (to-one)
List<UriResource> resourceParts = uriInfo.getUriResourceParts();
int segmentCount = resourceParts.size();
UriResource uriResource = resourceParts.get(0); // in our example, the
// first segment is the
// EntitySet
if (!(uriResource instanceof UriResourceEntitySet)) {
throw new ODataApplicationException(“Only EntitySet is supported”,
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
Locale.ENGLISH);
}
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) uriResource;
EdmEntitySet startEdmEntitySet = uriResourceEntitySet.getEntitySet();
// Analyze the URI segments
if (segmentCount == 1) {
// no navigation
responseEdmEntityType = startEdmEntitySet.getEntityType();
responseEdmEntitySet = startEdmEntitySet; // since we have only one
//http://localhost:8088/school_stu_teachers/DemoService.svc/Schools(‘psg‘)
if(responseEdmEntityType.getName().equals(DemoEdmProvider.ET_SCHOOL_NAME))
{
List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
//get the school entity that has name psg
responseEntity=storage.readEntityDataFromDatabase(responseEdmEntitySet,keyPredicates);
}
} else if (segmentCount == 2) {
//eg..Students(1)/School
System.out.println(“segment count 2”);
// navigation
UriResource navSegment = resourceParts.get(1); //so gets school entity set
if (navSegment instanceof UriResourceNavigation) {
UriResourceNavigation uriResourceNavigation = (UriResourceNavigation) navSegment;
EdmNavigationProperty edmNavigationProperty = uriResourceNavigation.getProperty();
responseEdmEntityType = edmNavigationProperty.getType();
// contextURL displays the last segment
//System.out.println(“”+startEdmEntitySet.getEntityType());
responseEdmEntitySet = Util.getNavigationTargetEntitySet(
startEdmEntitySet, edmNavigationProperty);
List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
// fetch the data from backend.
// e.g. for Students(1)/School we have to find first Students(1)
Entity sourceEntity = storage.readEntityData(startEdmEntitySet,keyPredicates);
// now we have to check if the navigation is
// a) to-one: e.g. Students(1)/School
// b) to-many with key: e.g. Schools(‘psg‘)/Students(5)
// the key for nav is used in this case:
// Schools(‘psg‘)/Students(5)
List<UriParameter> navKeyPredicates = uriResourceNavigation.getKeyPredicates();
if (navKeyPredicates.isEmpty()) { // e.g. DemoService.svc/Students(1)/School
responseEntity = storage.getRelatedEntity(sourceEntity,
responseEdmEntityType);
} else { // e.g. DemoService.svc/Schools(3)/Students(5)
responseEntity = storage.getRelatedEntity(sourceEntity,
responseEdmEntityType, navKeyPredicates);
}
}
} else {
// this would be the case for e.g.
// Students(1)/School/Students(1)/School
throw new ODataApplicationException(“Not supported”,
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
if (responseEntity == null) {
// this is the case for e.g. DemoService.svc/Schools(‘psg‘) or
// DemoService.svc/Schools(‘psg‘)/Students(999) where student with id 999 not exists
throw new ODataApplicationException(“Nothing found.”,
HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
}
SelectOption selectOption = uriInfo.getSelectOption();
ExpandOption expandOption = uriInfo.getExpandOption();
// in our example: http://localhost:8080/school_stu_teachers/DemoService.svc/Schools(‘psg’)/$expand=Students
// or http://localhost:8080/school_stu_teachers/DemoService.svc/Students(1)?$expand=Schools
if(expandOption != null) {
//since more than 1 expand option eg. students,teachers
for(int i=0;i<expandOption.getExpandItems().size();i++)
{
// retrieve the EdmNavigationProperty from the expand expression
// Note: in our example, we have only one NavigationProperty, so we can directly access it
EdmNavigationProperty edmNavigationProperty = null;
ExpandItem expandItem = expandOption.getExpandItems().get(i);
if(expandItem.isStar()) {
List<EdmNavigationPropertyBinding> bindings = responseEdmEntitySet.getNavigationPropertyBindings();
// we know that there are navigation bindings
// however normally in this case a check if navigation bindings exists is done
if(!bindings.isEmpty()) {
//since we have more than 1 nav bindings
EdmNavigationPropertyBinding binding = bindings.get(i);
EdmElement property = responseEdmEntitySet.getEntityType().getProperty(binding.getPath());
// we don’t need to handle error cases, as it is done in the Olingo library
if(property instanceof EdmNavigationProperty) {
edmNavigationProperty = (EdmNavigationProperty) property;
}
}
} else {
// can be ‘School’ or ‘Students’, no path supported
UriResource expandUriResource = expandItem.getResourcePath().getUriResourceParts().get(0);
// we don’t need to handle error cases, as it is done in the Olingo library
if(expandUriResource instanceof UriResourceNavigation) {
edmNavigationProperty = ((UriResourceNavigation) expandUriResource).getProperty();
}
}
// can be ‘School’ or ‘Students’, no path supported
// we don’t need to handle error cases, as it is done in the Olingo library
if(edmNavigationProperty != null) {
EdmEntityType expandEdmEntityType = edmNavigationProperty.getType();
String navPropName = edmNavigationProperty.getName();
// build the inline data
Link link = new Link();
link.setTitle(navPropName);
link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
link.setRel(Constants.NS_ASSOCIATION_LINK_REL + navPropName);
if(edmNavigationProperty.isCollection()) { // in case of Schools(‘psg‘)/$expand=Students
// fetch the data for the $expand (to-many navigation) from backend
// here we get the data for the expand
System.out.println(“iscollection”);
//get students of given school
EntityCollection expandEntityCollection =
storage.getRelatedEntityCollection(responseEntity, expandEdmEntityType);
link.setInlineEntitySet(expandEntityCollection);
link.setHref(expandEntityCollection.getId().toASCIIString());
} else { // in case of Students(1)?$expand=School
// fetch the data for the $expand (to-one navigation) from backend
// here we get the data for the expand
//get school of given student
Entity expandEntity = storage.getRelatedEntity(responseEntity, expandEdmEntityType);
link.setInlineEntity(expandEntity);
link.setHref(expandEntity.getId().toASCIIString());
}
// set the link – containing the expanded data – to the current entity
responseEntity.getNavigationLinks().add(link);
}
}
// 3. serialize
EdmEntityType edmEntityType = responseEdmEntitySet.getEntityType();
// we need the property names of the $select, in order to build the context URL
String selectList = odata.createUriHelper().buildContextURLSelectList(edmEntityType, expandOption, selectOption);
ContextURL contextUrl = ContextURL.with().entitySet(responseEdmEntitySet)
.selectList(selectList)
.suffix(Suffix.ENTITY).build();
// make sure that $expand and $select are considered by the serializer
// adding the selectOption to the serializerOpts will actually tell the lib to do the job
EntitySerializerOptions opts = EntitySerializerOptions.with()
.contextURL(contextUrl)
.select(selectOption)
.expand(expandOption)
.build();
ODataSerializer serializer = this.odata.createSerializer(responseFormat);
SerializerResult serializerResult = serializer.entity(srvMetadata, edmEntityType, responseEntity, opts);
// 5. configure the response object
response.setContent(serializerResult.getContent());
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
}
//if expand null
else{
ContextURL contextUrl =
ContextURL.with().entitySet(responseEdmEntitySet).suffix(Suffix.ENTITY).build();
EntitySerializerOptions opts =
EntitySerializerOptions.with().contextURL(contextUrl).build();
ODataSerializer serializer =
this.odata.createSerializer(responseFormat);
SerializerResult serializerResult =
serializer.entity(this.srvMetadata,
responseEdmEntityType, responseEntity, opts);
// 4. configure the response object
response.setContent(serializerResult.getContent());
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE,
responseFormat.toContentTypeString());}
}
- b. Create createEntity method that gets called on ‘POST’ request:
public void createEntity(ODataRequest request, ODataResponse response,
UriInfo uriInfo, ContentType requestFormat,
ContentType responseFormat) throws ODataApplicationException,
DeserializerException, SerializerException {
List<StudentDto> studList=new ArrayList<StudentDto>();
EdmEntityType responseEdmEntityType = null; // we’ll need this to build
// response body
EdmEntitySet responseEdmEntitySet = null; // we need this for building
// the contextUrl
// 1st step: retrieve the requested Entity: can be “normal” read
// operation, or navigation (to-one)
List<UriResource> resourceParts = uriInfo.getUriResourceParts();
int segmentCount = resourceParts.size();
UriResource uriResource = resourceParts.get(0); // in our example, the
first segment is the EntitySet
if (!(uriResource instanceof UriResourceEntitySet)) {
throw new ODataApplicationException(“Only EntitySet is supported”,
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
Locale.ENGLISH);
}
UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) uriResource;
EdmEntitySet startEdmEntitySet = uriResourceEntitySet.getEntitySet();
// Analyze the URI segments
if (segmentCount == 1) { // no navigation
responseEdmEntityType = startEdmEntitySet.getEntityType();
responseEdmEntitySet = startEdmEntitySet; // since we have only one
if (responseEdmEntityType.getName().equals(DemoEdmProvider.ET_STUDENT_NAME))
{
EntityCollection ec=new EntityCollection();
//get data(body) from post
InputStream requestInputStream = request.getBody();
InputStream is = null;
try {
ObjectMapper mapper = new ObjectMapper();
// convert inputstream to json
List<Map<String, Object>> jsonmap = mapper.readValue(
requestInputStream,
new TypeReference<List<Map<String, Object>>>() {
});
for (Map<String, Object> a : jsonmap) {
SchoolDto s=new SchoolDto();
SchoolDo d=new SchoolDo();
List<Map<String, Object>> stdo=new ArrayList<Map<String, Object>>();
Map<String, Object> b=new HashMap<String, Object>();
String school_name=(String) a.get(“school_name”);
s=dao.readSchoolData(school_name);
d=s.getEntity(s);
System.out.println(a.get(“studentsDto”));
stdo= (List<Map<String, Object>>) a.get(“studentsDto”);
System.out.println(stdo.size());
for(Map<String, Object> i:stdo)
{
StudentDto stuDto=new StudentDto();
ServiceDao dao = new ServiceDao();
StudentDo stuDo=new StudentDo();
b.put(“stu_name”, i.get(“stu_name”));
String mapAsJson = new ObjectMapper().writeValueAsString(b);
//Converting json string to java object
StudentDto stud= (StudentDto) fromJson(mapAsJson);
//get studentdo from dto
stuDo=stuDto.getEntity(stud);
stuDo.setSchoolIdRef(d);
dao.create(stuDo);
}
}
}
catch(Exception e)
{System.out.println(e.getMessage());}
// 4. configure the response object
// response.setContent(serializedResponse.getContent());
response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE,
responseFormat.toContentTypeString());
}
else if(responseEdmEntityType.getName().equals(DemoEdmProvider.ET_SCHOOL_NAME))
{
InputStream requestInputStream = request.getBody();
try {
ObjectMapper mapper = new ObjectMapper();
//read data (body of post) and convert it to list of maps
List<Map<String, Object>> jsonmap = mapper.readValue(
requestInputStream,
new TypeReference<List<Map<String, Object>>>() {
});
Map<String, Object> b=new HashMap<String, Object>();
for (Map<String, Object> a : jsonmap) {
// Set<String> b = a.keySet();
for (String i : a.keySet()) {
System.out.println(“key “ + i + ” value “ + a.get(i));
}
b.put(“school_id”, a.get(“school_id”));
b.put(“schoolName”, a.get(“school_name”));
b.put(“studentsDto”, a.get(“studentsDto”
b.put(“teachersDto”, a.get(“teachersDto”));
String mapAsJson = new ObjectMapper().writeValueAsString(b);
//Converting json string to java object
SchoolDto scho= (SchoolDto) fromJson1(mapAsJson);
//create an object in DB
SchoolDto schoolDto=new SchoolDto();
SchoolServiceDao dao = new SchoolServiceDao();
SchoolDo schoolDo=new SchoolDo();
List<SchoolDo> schoolDoList =new ArrayList<SchoolDo>();
//get schooldo from dto
schoolDo=schoolDto.getEntity(scho);
schoolDoList.add(schoolDo);
try {
System.out.println(mapAsJson);
} catch (Exception e) {
System.out.println(“Exception:”+e.getMessage());
}
System.out.println(“hao”);
dao.create(schoolDoList);
}
} catch (Exception e1) {
System.out.println(“Exception1:”+e1.getMessage());
}
// 4. configure the response object
// response.setContent(serializedResponse.getContent());
response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE,
responseFormat.toContentTypeString());
}
} else if (segmentCount == 2) {
throw new ODataApplicationException(“Not implemented”,
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
} else {
// this would be the case for e.g.
// Students(1)/School/Students(1)/School
throw new ODataApplicationException(“Not supported”,
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
}