package eu.europeana.cloud.service.uis.rest;
import javax.ws.rs.DELETE;
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.MediaType;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.stereotype.Component;
import com.qmino.miredot.annotations.ReturnType;
import eu.europeana.cloud.common.exceptions.ProviderDoesNotExistException;
import eu.europeana.cloud.common.model.CloudId;
import eu.europeana.cloud.common.model.LocalId;
import eu.europeana.cloud.common.response.ResultSlice;
import eu.europeana.cloud.common.web.UISParamConstants;
import eu.europeana.cloud.service.aas.authentication.SpringUserUtils;
import eu.europeana.cloud.service.uis.UniqueIdentifierService;
import eu.europeana.cloud.service.uis.exception.CloudIdAlreadyExistException;
import eu.europeana.cloud.service.uis.exception.CloudIdDoesNotExistException;
import eu.europeana.cloud.service.uis.exception.DatabaseConnectionException;
import eu.europeana.cloud.service.uis.exception.RecordDatasetEmptyException;
import eu.europeana.cloud.service.uis.exception.RecordDoesNotExistException;
import eu.europeana.cloud.service.uis.exception.RecordExistsException;
import eu.europeana.cloud.service.uis.exception.RecordIdDoesNotExistException;
import java.util.List;
/**
* Implementation of the Unique Identifier Service.
*
* @author Yorgos.Mamakis@ kb.nl
* @since Oct 17, 2013
*/
@Component
@Path("/cloudIds")
@Scope("request")
public class UniqueIdentifierResource {
@Autowired
private UniqueIdentifierService uniqueIdentifierService;
@Autowired
private DataProviderResource dataProviderResource;
private static final String CLOUDID = "cloudId";
@Autowired
private MutableAclService mutableAclService;
private final String CLOUD_ID_CLASS_NAME = CloudId.class.getName();
/**
* Invokes the generation of a cloud identifier using the provider
* identifier and a record identifier.
*
* <br/>
* <br/>
* <div style='border-left: solid 5px #999999; border-radius: 10px; padding:
* 6px;'> <strong>Required permissions:</strong>
* <ul>
* <li>Authenticated user</li>
* </ul>
* </div>
*
* @summary Cloud identifier generation
* @param providerId
* <strong>REQUIRED</strong> identifier of data-provider for
* which new cloud identifier will be created.
* @param localId
* record identifier which will be binded to the newly created
* cloud identifier. If not provided, random value will be
* generated.
* @return The newly created CloudId
* @throws DatabaseConnectionException
* database error
* @throws RecordExistsException
* Record already exists in repository
* @throws ProviderDoesNotExistException
* Supplied Data-provider does not exist
* @throws RecordDatasetEmptyException
* dataset is empty
* @throws CloudIdDoesNotExistException
* cloud identifier does not exist
* @throws CloudIdAlreadyExistException
* Cloud identifier was created previously
*/
@POST
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@ReturnType("eu.europeana.cloud.common.model.CloudId")
@PreAuthorize("isAuthenticated()")
public Response createCloudId(@QueryParam(UISParamConstants.Q_PROVIDER) String providerId,
@QueryParam(UISParamConstants.Q_RECORD_ID) String localId)
throws DatabaseConnectionException, RecordExistsException, ProviderDoesNotExistException,
RecordDatasetEmptyException, CloudIdDoesNotExistException, CloudIdAlreadyExistException {
final CloudId cId = (localId != null) ? (uniqueIdentifierService.createCloudId(providerId, localId))
: (uniqueIdentifierService.createCloudId(providerId));
final Response response = Response.ok().entity(cId).build();
// CloudId created => let's assign permissions to the owner
String creatorName = SpringUserUtils.getUsername();
if (creatorName != null) {
ObjectIdentity cloudIdIdentity = new ObjectIdentityImpl(CLOUD_ID_CLASS_NAME, cId.getId());
MutableAcl cloudIdAcl = mutableAclService.createAcl(cloudIdIdentity);
cloudIdAcl.insertAce(0, BasePermission.READ, new PrincipalSid(creatorName), true);
cloudIdAcl.insertAce(1, BasePermission.WRITE, new PrincipalSid(creatorName), true);
cloudIdAcl.insertAce(2, BasePermission.DELETE, new PrincipalSid(creatorName), true);
cloudIdAcl.insertAce(3, BasePermission.ADMINISTRATION, new PrincipalSid(creatorName), true);
mutableAclService.updateAcl(cloudIdAcl);
}
dataProviderResource.grantPermissionsToLocalId(cId, providerId);
return response;
}
/**
* Retrieves cloud identifier based on given provider identifier and record
* identifier
*
* @summary Cloud identifier retrieval
* @param providerId
* <strong>REQUIRED</strong> provider identifier
* @param recordId
* <strong>REQUIRED</strong> record identifier
*
* @return Cloud identifier associated with given provider identifier and
* record identifier
*
* @throws DatabaseConnectionException
* database error
* @throws RecordDoesNotExistException
* record does not exist
* @throws ProviderDoesNotExistException
* provider does not exist
* @throws RecordDatasetEmptyException
* dataset is empty
*/
@GET
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@ReturnType("eu.europeana.cloud.common.model.CloudId")
public Response getCloudId(@QueryParam(UISParamConstants.Q_PROVIDER) String providerId,
@QueryParam(UISParamConstants.Q_RECORD_ID) String recordId)
throws DatabaseConnectionException, RecordDoesNotExistException, ProviderDoesNotExistException,
RecordDatasetEmptyException {
return Response.ok(uniqueIdentifierService.getCloudId(providerId, recordId)).build();
}
/**
* Retrieves list of record Identifiers associated with the cloud
* identifier. Result is returned in slices which contain fixed amount of
* results and reference (token) to next slice of results.
*
* @summary List of record identifiers retrieval
*
* @param cloudId
* <strong>REQUIRED</strong> cloud identifier for which list of
* all record identifiers will be retrieved
*
* @return The list of record identifiers bound to given provider identifier
*
* @throws DatabaseConnectionException
* database error
* @throws CloudIdDoesNotExistException
* cloud identifier does not exist
* @throws ProviderDoesNotExistException
* provider does not exist
* @throws RecordDatasetEmptyException
* datset is empty
*
*/
@GET
@Path("{" + CLOUDID + "}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@ReturnType("eu.europeana.cloud.common.response.ResultSlice<eu.europeana.cloud.common.model.CloudId>")
public Response getLocalIds(@PathParam(CLOUDID) String cloudId)
throws DatabaseConnectionException, CloudIdDoesNotExistException, ProviderDoesNotExistException,
RecordDatasetEmptyException {
ResultSlice<CloudId> pList = new ResultSlice<>();
pList.setResults(uniqueIdentifierService.getLocalIdsByCloudId(cloudId));
return Response.ok(pList).build();
}
/**
* Remove a cloud identifier and all the associations to its record
* identifiers
*
* <br/>
* <br/>
* <div style='border-left: solid 5px #999999; border-radius: 10px; padding:
* 6px;'> <strong>Required permissions:</strong>
* <ul>
* <li>Admin role</li>
* </ul>
* </div>
*
* @summary Cloud identifier removal
*
* @param cloudId
* <strong>REQUIRED</strong> cloud identifier which will be
* removed
*
* @return Empty response with http status code indicating whether the
* operation was successful or not
*
* @throws DatabaseConnectionException
* database error
* @throws CloudIdDoesNotExistException
* cloud identifier does not exist
* @throws ProviderDoesNotExistException
* provider does not exist
* @throws RecordIdDoesNotExistException
* record identifier does not exist
*/
@DELETE
@Path("{" + CLOUDID + "}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@PreAuthorize("hasRole('ROLE_ADMIN')")
public Response deleteCloudId(@PathParam(CLOUDID) String cloudId)
throws DatabaseConnectionException, CloudIdDoesNotExistException, ProviderDoesNotExistException,
RecordIdDoesNotExistException {
// usuwanie cloudId local id tworznego przy tworznie clouId
//sprawdzić co się stanie po dodaniu mapowania wiele razy i uunięcu cloudId
//dopisac
List<CloudId> removedCloudIds = uniqueIdentifierService.deleteCloudId(cloudId);
for (CloudId cId : removedCloudIds) {
dataProviderResource.deleteLocalIdAcl(cId.getLocalId().getRecordId(), cId.getLocalId().getProviderId());
}
// let's delete the permissions as well
ObjectIdentity cloudIdentity = new ObjectIdentityImpl(CLOUD_ID_CLASS_NAME, cloudId);
mutableAclService.deleteAcl(cloudIdentity, false);
return Response.ok("CloudId marked as deleted").build();
}
}