All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anotheria.anosite.photoserver.api.photo.ceph.PhotoCephClientService Maven / Gradle / Ivy

The newest version!
package net.anotheria.anosite.photoserver.api.photo.ceph;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectInputStream;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import net.anotheria.anoprise.dualcrud.CrudService;
import net.anotheria.anoprise.dualcrud.CrudServiceException;
import net.anotheria.anoprise.dualcrud.ItemNotFoundException;
import net.anotheria.anoprise.dualcrud.Query;
import net.anotheria.anoprise.dualcrud.SaveableID;
import net.anotheria.anosite.photoserver.api.photo.PhotoFileHolder;
import net.anotheria.anosite.photoserver.api.photo.PhotoStorageUtil;
import net.anotheria.moskito.core.dynamic.OnDemandStatsProducer;
import net.anotheria.moskito.core.registry.ProducerRegistryFactory;
import net.anotheria.util.concurrency.IdBasedLock;
import net.anotheria.util.concurrency.IdBasedLockManager;
import net.anotheria.util.concurrency.SafeIdBasedLockManager;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * Implementation for ceph service for store photos.
 *
 * @author ykalapusha
 */
public class PhotoCephClientService implements CrudService {
    /**
     * {@link Logger} instance.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(PhotoCephClientService.class);
    /**
     * Lock manager for safe operations with files.
     */
    private static final IdBasedLockManager LOCK_MANAGER = new SafeIdBasedLockManager<>();
    /**
     * {@link AmazonS3} client.
     */
    private final AmazonS3 amazonS3Connection;
    /**
     * Bucket name.
     */
    private final String bucketName;
    /**
     * {@link OnDemandStatsProducer} instance.
     */
    private final OnDemandStatsProducer statsProducer;

    /**
     * Constructor.
     */
    public PhotoCephClientService() {

        statsProducer = new OnDemandStatsProducer<>("CephPhotos", "business", "api", new PhotoCephClientStatsFactory());
        ProducerRegistryFactory.getProducerRegistryInstance().registerProducer(statsProducer);

        PhotoCephClientConfig cephClientConfig = PhotoCephClientConfig.getInstance();
        bucketName = cephClientConfig.getBucket();
        AWSCredentials credentials = new BasicAWSCredentials(cephClientConfig.getAccessKey(), cephClientConfig.getSecretKey());
        ClientConfiguration clientConfig = new ClientConfiguration();
        clientConfig.setProtocol(Protocol.HTTP);
        amazonS3Connection = new AmazonS3Client(credentials, clientConfig);
        amazonS3Connection.setEndpoint(cephClientConfig.getEndpoint());
    }


    @Override
    public PhotoFileHolder create(PhotoFileHolder photoFileHolder) throws CrudServiceException {
        statsProducer.getDefaultStats().incPhotosToAdd();
        IdBasedLock lock = LOCK_MANAGER.obtainLock(photoFileHolder.getOwnerId());
        lock.lock();

        //first of all we try to write into the ceph storage, so we will read input stream and can not use it for second dual crud service, that`s why we create new one.
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            IOUtils.copyLarge(photoFileHolder.getPhotoFileInputStream(), baos);
            byte[] bytes = baos.toByteArray();

            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(bytes.length);

            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, photoFileHolder.getOwnerId(), photoFileHolder.getPhotoFileInputStream(), objectMetadata);
            amazonS3Connection.putObject(putObjectRequest);
            statsProducer.getDefaultStats().incAddedPhotos();
            return photoFileHolder;
        } catch (Exception e) {
            statsProducer.getDefaultStats().incCrudErrors();
            throw new CrudServiceException(e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(baos);
            lock.unlock();
        }
    }

    @Override
    public PhotoFileHolder read(SaveableID id) throws CrudServiceException, ItemNotFoundException {
        statsProducer.getDefaultStats().incPhotosToRead();
        IdBasedLock lock = LOCK_MANAGER.obtainLock(id.getOwnerId());
        lock.lock();
        try {
            final S3Object s3Object = amazonS3Connection.getObject(bucketName, id.getOwnerId());
            S3ObjectInputStream inputStream = s3Object.getObjectContent();
            String userId = id.getSaveableId().split("______USER_ID______")[1];
            PhotoFileHolder photoFileHolder = new PhotoFileHolder(PhotoStorageUtil.getId(id.getOwnerId()), PhotoStorageUtil.getOriginalId(id.getOwnerId()), PhotoStorageUtil.getExtension(id.getOwnerId()), userId);
            photoFileHolder.setPhotoFileInputStream(inputStream);
            statsProducer.getDefaultStats().incReadPhotos();
            return photoFileHolder;
        } catch (AmazonS3Exception e) {
            if (e.getErrorCode().equals("NoSuchKey")) {
                statsProducer.getDefaultStats().incNotFoundPhotos();
                throw new ItemNotFoundException(e.getMessage());
            }

            LOGGER.error("Unable to read object", e);
            statsProducer.getDefaultStats().incCrudErrors();
            throw new CrudServiceException("Unable to read object", e);
        } catch (IOException e) {
            throw new CrudServiceException(e.getMessage(), e);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public PhotoFileHolder update(PhotoFileHolder photoFileHolder) throws CrudServiceException {
        return create(photoFileHolder);
    }

    @Override
    public void delete(PhotoFileHolder photoFileHolder) throws CrudServiceException {
        statsProducer.getDefaultStats().incPhotosToRemove();
        try {
            amazonS3Connection.deleteObject(bucketName, photoFileHolder.getOwnerId());

            //delete cached versions
            ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
            listObjectsRequest.setBucketName(bucketName);
            listObjectsRequest.setPrefix(photoFileHolder.getOriginalPhotoId() + "_");

            ObjectListing objectListing = amazonS3Connection.listObjects(listObjectsRequest);
            for (S3ObjectSummary summary :objectListing.getObjectSummaries()) {
                amazonS3Connection.deleteObject(bucketName, summary.getKey());
            }
            statsProducer.getDefaultStats().incRemovedPhotos();
        } catch (Exception e) {
            statsProducer.getDefaultStats().incCrudErrors();
            LOGGER.error("Unable to delete photo from ceph: " + e.getMessage());
        }
    }

    @Override
    public PhotoFileHolder save(PhotoFileHolder photoFileHolder) throws CrudServiceException {
        return create(photoFileHolder);
    }

    @Override
    public boolean exists(PhotoFileHolder photoFileHolder) throws CrudServiceException {
        statsProducer.getDefaultStats().incIsPhotoExistsCheck();
        return amazonS3Connection.doesObjectExist(bucketName, photoFileHolder.getOwnerId());
    }

    @Override
    public List query(Query q) throws CrudServiceException {
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy