blob: b45f709aaf2fd3a36ec12673cb6eb462a1ae4baf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013-2020 LAAS-CNRS (www.laas.fr)
* 7 Colonel Roche 31077 Toulouse - France
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Initial Contributors:
* Thierry Monteil : Project manager, technical co-manager
* Mahdi Ben Alaya : Technical co-manager
* Samir Medjiah : Technical co-manager
* Khalil Drira : Strategy expert
* Guillaume Garzone : Developer
* François Aïssaoui : Developer
*
* New contributors :
*******************************************************************************/
package org.eclipse.om2m.core.controller;
import java.math.BigInteger;
import java.util.List;
import org.eclipse.om2m.commons.constants.Constants;
import org.eclipse.om2m.commons.constants.MimeMediaType;
import org.eclipse.om2m.commons.constants.ResourceStatus;
import org.eclipse.om2m.commons.constants.ResourceType;
import org.eclipse.om2m.commons.constants.ResponseStatusCode;
import org.eclipse.om2m.commons.constants.ShortName;
import org.eclipse.om2m.commons.entities.AccessControlPolicyEntity;
import org.eclipse.om2m.commons.entities.ContainerEntity;
import org.eclipse.om2m.commons.entities.ContentInstanceEntity;
import org.eclipse.om2m.commons.entities.ResourceEntity;
import org.eclipse.om2m.commons.entities.SubscriptionEntity;
import org.eclipse.om2m.commons.exceptions.BadRequestException;
import org.eclipse.om2m.commons.exceptions.ConflictException;
import org.eclipse.om2m.commons.exceptions.NotImplementedException;
import org.eclipse.om2m.commons.exceptions.OperationNotAllowed;
import org.eclipse.om2m.commons.exceptions.ResourceNotFoundException;
import org.eclipse.om2m.commons.resource.ContentInstance;
import org.eclipse.om2m.commons.resource.RequestPrimitive;
import org.eclipse.om2m.commons.resource.ResponsePrimitive;
import org.eclipse.om2m.core.datamapper.DataMapperSelector;
import org.eclipse.om2m.core.entitymapper.EntityMapperFactory;
import org.eclipse.om2m.core.notifier.Notifier;
import org.eclipse.om2m.core.persistence.PersistenceService;
import org.eclipse.om2m.core.router.Patterns;
import org.eclipse.om2m.core.urimapper.UriMapper;
import org.eclipse.om2m.core.util.ControllerUtil;
import org.eclipse.om2m.persistence.service.DAO;
import org.eclipse.om2m.persistence.service.DBService;
import org.eclipse.om2m.persistence.service.DBTransaction;
/**
* Controller for the content instance resource
*
*/
public class ContentInstanceController extends Controller {
/**
* do create operation for contentInstance
* @param request
* @return response
*/
@Override
public ResponsePrimitive doCreate(RequestPrimitive request) {
/*
* ContentInstance creation procedure
*
* @resourceName NP
* resourceType NP
* resourceID NP
* parentID NP
* creationTime NP
* expirationTime O?
* lastModifiedTime NP
* labels O
* announceTo O
* announcedAttribute NP
*
* creator O
* contentInfo M
* contentSize O
* ontologyRef O
* content M
*
*/
// create the response
ResponsePrimitive response = new ResponsePrimitive(request);
Patterns patterns = new Patterns();
// get the dao of the parent
@SuppressWarnings("unchecked")
DAO<ResourceEntity> parentDAO = (DAO<ResourceEntity>) patterns.getDAO(request.getTo(), dbs);
if (parentDAO == null) {
throw new ResourceNotFoundException("Cannot find parent resource");
}
// get the parent entity
ResourceEntity parentEntity = parentDAO.find(transaction, request.getTo());
// check the parent existence
if (parentEntity == null) {
throw new ResourceNotFoundException("Cannot find parent resource");
}
// get lists to change in the method corresponding to specific object
List<AccessControlPolicyEntity> acpsToCheck = null;
List<SubscriptionEntity> subscriptions = null;
// different cases
// case parent is Container
if (parentEntity.getResourceType().intValue() == (ResourceType.CONTAINER)) {
ContainerEntity container = (ContainerEntity) parentEntity;
acpsToCheck = container.getAccessControlPolicies();
subscriptions = container.getSubscriptions();
} else if (parentEntity.getResourceType().intValue() == (ResourceType.CONTAINER_ANNC)) {
// case parent is ContainerAnnc
throw new NotImplementedException("Parent is Container Annc, not implemented yet.");
}
// Check acp
checkACP(acpsToCheck, request.getFrom(), request.getOperation());
// check if content is present
if (request.getContent() == null){
throw new BadRequestException("A content is requiered for ContentInstance creation");
}
// get the object from the representation
ContentInstance cin = null;
try{
if (request.getRequestContentType().equals(MimeMediaType.OBJ)){
cin = (ContentInstance) request.getContent();
} else {
cin = (ContentInstance)DataMapperSelector.getDataMapperList()
.get(request.getRequestContentType()).stringToObj((String)request.getContent());
}
} catch (ClassCastException e){
throw new BadRequestException("Incorrect resource representation in content", e);
}
if (cin == null){
throw new BadRequestException("Error in provided content");
}
ContentInstanceEntity cinEntity = new ContentInstanceEntity();
// check attributes
// @resourceName NP
// Resource Type NP
// resourceID NP
// parentID NP
// lastModifiedTime NP
// creationTime NP
// labels O
ControllerUtil.CreateUtil.fillEntityFromGenericResource(cin, cinEntity);
// announcedAttribute O
if (!cin.getAnnouncedAttribute().isEmpty()) {
cinEntity.getAnnouncedAttribute().addAll(cin.getAnnouncedAttribute());
}
// contentInfo M
if (cin.getContentInfo() == null) {
cinEntity.setContentInfo("text/plain:0");
} else {
cinEntity.setContentInfo(cin.getContentInfo());
}
// content M
if (cin.getContent() == null) {
throw new BadRequestException("Content is Mandatory");
}
String generatedId = generateId("", "");
cinEntity.setResourceID("/" + Constants.CSE_ID + "/" + ShortName.CIN
+ Constants.PREFIX_SEPERATOR + generatedId);
// check & set resource name if present
if (cin.getName() != null){
if (!patterns.checkResourceName(cin.getName())){
throw new BadRequestException("Name provided is incorrect. Must be:" + patterns.ID_STRING);
}
cinEntity.setName(cin.getName());
} else {
cinEntity.setName(ShortName.CIN + "_" + generatedId);
}
cinEntity.setHierarchicalURI(parentEntity.getHierarchicalURI() + "/" + cinEntity.getName());
if (! UriMapper.addNewUri(cinEntity.getHierarchicalURI(), cinEntity.getResourceID(),
ResourceType.CONTENT_INSTANCE)) {
throw new ConflictException("Name already present in the parent collection.");
}
cinEntity.setParentID(parentEntity.getResourceID());
cinEntity.setResourceType(ResourceType.CONTENT_INSTANCE);
cinEntity.setContent(cin.getContent());
cinEntity.setStateTag(BigInteger.valueOf(0));
// creator O
if (cin.getCreator() != null) {
cinEntity.setCreator(cin.getCreator());
}
// expiration time O?
if (cin.getExpirationTime() != null){
cinEntity.setExpirationTime(cin.getExpirationTime());
}
// announceTo O
if (!cin.getAnnounceTo().isEmpty()){
cinEntity.getAnnounceTo().addAll(cin.getAnnounceTo());
}
// ontologyRef O
if (cin.getOntologyRef() != null){
cinEntity.setOntologyRef(cin.getOntologyRef());
}
DAO<ContentInstanceEntity> ciDAO = dbs.getDAOFactory().getContentInstanceDAO();
// case parent is Container
if (parentEntity.getResourceType().intValue() == (ResourceType.CONTAINER)) {
ContainerEntity container = (ContainerEntity) parentEntity;
if (container.getMaxNrOfInstances() != null) {
if (container.getCurrentNrOfInstances().intValue() >= container.getMaxNrOfInstances().intValue()) {
LOGGER.info("Deleting oldest content instance due to container size limit");
ContentInstanceEntity oldCI = dbs.getDAOFactory().getOldestDAO().find(transaction, request.getTo());
ciDAO.delete(transaction, oldCI);
UriMapper.deleteUri(oldCI.getHierarchicalURI());
} else {
container.setCurrentNrOfInstances(BigInteger.valueOf(container.getCurrentNrOfInstances().intValue()+1));
}
}
cinEntity.setParentContainer(container);
if(container.getStateTag() != null){
container.setStateTag(BigInteger.valueOf(container.getStateTag().intValue() + 1));
}
}
// case parent is ContainerAnnc
if (parentEntity.getResourceType().intValue() == (ResourceType.CONTAINER_ANNC)) {
//TODO set parent containerAnnc when implemented
}
// create the contentInstance in the DB
ciDAO.create(transaction, cinEntity);
// commit the transaction
transaction.commit();
Notifier.notify(subscriptions, cinEntity, ResourceStatus.CHILD_CREATED);
// create the response
response.setResponseStatusCode(ResponseStatusCode.CREATED);
// set the location of the resource
setLocationAndCreationContent(request, response, cinEntity);
return response;
}
/**
* Generic do retrieve operation
* @param request
* @return response
*/
@Override
public ResponsePrimitive doRetrieve(RequestPrimitive request) {
// create the response primitive
ResponsePrimitive response = new ResponsePrimitive(request);
// check existence of the resource
ContentInstanceEntity cinEntity = dbs.getDAOFactory().getContentInstanceDAO().find(transaction, request.getTo());
if (cinEntity == null) {
throw new ResourceNotFoundException("Resource not found");
}
// check authorization
List<AccessControlPolicyEntity> acpList = cinEntity.getAcpListFromParent();
checkACP(acpList, request.getFrom(), request.getOperation());
// mapping the entity with the exchange resource
ContentInstance cin = EntityMapperFactory.getContentInstanceMapper().
mapEntityToResource(cinEntity, request);
response.setContent(cin);
response.setResponseStatusCode(ResponseStatusCode.OK);
// return the completed response
return response;
}
/**
* Full update for Content Instance
*/
@Override
public ResponsePrimitive doUpdate(RequestPrimitive request) {
// this operation is not allowed for content instance resource
throw new OperationNotAllowed("Update on ContentInstance is not Allowed");
}
/**
* Generic delete procedure
*/
@Override
public ResponsePrimitive doDelete(RequestPrimitive request) {
// create the response primitive
ResponsePrimitive response = new ResponsePrimitive(request);
Patterns patterns = new Patterns();
// get the database service
DBService dbs = PersistenceService.getInstance().getDbService();
DBTransaction transaction = dbs.getDbTransaction();
// open the transaction
transaction.open();
// retrieve the target resource from database
ContentInstanceEntity cin = dbs.getDAOFactory()
.getContentInstanceDAO().find(transaction, request.getTo());
if (cin == null) {
throw new ResourceNotFoundException("Resource not found");
}
// check the access control policies
checkACP(cin.getAcpListFromParent(),
request.getFrom(), request.getOperation());
UriMapper.deleteUri(cin.getHierarchicalURI());
@SuppressWarnings("unchecked")
DAO<ResourceEntity> parentDAO = (DAO<ResourceEntity>) patterns.getDAO(cin.getParentID(), dbs);
ResourceEntity parentEntity = parentDAO.find(transaction, cin.getParentID());
if (parentEntity.getResourceType().intValue() == (ResourceType.CONTAINER)) {
ContainerEntity container = (ContainerEntity) parentEntity;
int nbI = container.getCurrentNrOfInstances().intValue();
container.setCurrentNrOfInstances(BigInteger.valueOf(nbI-1));
dbs.getDAOFactory().getContainerDAO().update(transaction, container);
} else {
throw new NotImplementedException("Parent is Container Annc, not implemented yet.");
}
Notifier.notifyDeletion(null, cin);
// delete the resource
dbs.getDAOFactory().getContentInstanceDAO().delete(transaction, cin);
// commit the transaction
transaction.commit();
// return the correct response
response.setResponseStatusCode(ResponseStatusCode.DELETED);
return response;
}
}