ome.services.RawPixelsBean.java Source code

Java tutorial

Introduction

Here is the source code for ome.services.RawPixelsBean.java

Source

/*
 *   $Id$
 *
 *   Copyright 2006 University of Dundee. All rights reserved.
 *   Use is subject to license terms supplied in LICENSE.txt
 */

package ome.services;

import java.awt.Dimension;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import ome.annotations.RolesAllowed;
import ome.api.IPixels;
import ome.api.IRepositoryInfo;
import ome.api.RawPixelsStore;
import ome.api.ServiceInterface;
import ome.conditions.ApiUsageException;
import ome.conditions.ResourceError;
import ome.conditions.RootException;
import ome.conditions.ValidationException;
import ome.io.bioformats.BfPixelBuffer;
import ome.io.bioformats.BfPyramidPixelBuffer;
import ome.io.nio.DimensionsOutOfBoundsException;
import ome.io.nio.PixelBuffer;
import ome.io.nio.PixelsService;
import ome.model.IObject;
import ome.model.core.Pixels;
import ome.parameters.Parameters;
import ome.security.basic.BasicSecuritySystem;
import ome.services.messages.EventLogMessage;
import ome.util.ShallowCopy;
import ome.util.SqlAction;
import ome.util.Utils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

/**
 * Implementation of the RawPixelsStore stateful service.
 *
 * @author <br>
 *         Josh Moore&nbsp;&nbsp;&nbsp;&nbsp; <a
 *         href="mailto:josh.moore@gmx.de"> josh.moore@gmx.de</a>
 * @version 3.0 <small> (<b>Internal version:</b> $Revision$ $Date: 2005/07/05
 *          16:13:52 $) </small>
 * @since OMERO3
 */
@Transactional(readOnly = true)
public class RawPixelsBean extends AbstractStatefulBean implements RawPixelsStore {
    /** The logger for this particular class */
    private static Log log = LogFactory.getLog(RawPixelsBean.class);

    private static final long serialVersionUID = -6640632220587930165L;

    private Long id;

    private transient Long reset = null;

    private transient Pixels pixelsInstance;

    private transient PixelBuffer buffer;

    private transient PixelsService dataService;

    private transient IPixels metadataService;

    /** the disk space checking service */
    private transient IRepositoryInfo iRepositoryInfo;

    /** is file service checking for disk overflow */
    private transient boolean diskSpaceChecking;

    /** A copy buffer for the pixel retrieval. */
    private transient byte[] readBuffer;

    /** Pixels set cache. */
    private transient Map<Long, Pixels> pixelsCache;

    /** SQL action instance for this class. */
    private transient SqlAction sql;

    /** The server's OMERO data directory. */
    private transient String omeroDataDir;

    /**
     * default constructor
     */
    public RawPixelsBean() {
    }

    /**
     * overriden to allow Spring to set boolean
     * 
     * @param checking
     */
    public RawPixelsBean(boolean checking, String omeroDataDir) {
        this.diskSpaceChecking = checking;
        this.omeroDataDir = omeroDataDir;
    }

    public Class<? extends ServiceInterface> getServiceInterface() {
        return RawPixelsStore.class;
    }

    public final void setPixelsMetadata(IPixels metaService) {
        getBeanHelper().throwIfAlreadySet(this.metadataService, metaService);
        metadataService = metaService;
    }

    public final void setPixelsData(PixelsService dataService) {
        getBeanHelper().throwIfAlreadySet(this.dataService, dataService);
        this.dataService = dataService;
    }

    /**
     * Disk Space Usage service Bean injector
     * 
     * @param iRepositoryInfo
     *            an <code>IRepositoryInfo</code>
     */
    public final void setIRepositoryInfo(IRepositoryInfo iRepositoryInfo) {
        getBeanHelper().throwIfAlreadySet(this.iRepositoryInfo, iRepositoryInfo);
        this.iRepositoryInfo = iRepositoryInfo;
    }

    /**
     * SQL action Bean injector
     * @param sql a <code>SqlAction</code>
     */
    public final void setSqlAction(SqlAction sql) {
        getBeanHelper().throwIfAlreadySet(this.sql, sql);
        this.sql = sql;
    }

    // ~ Lifecycle methods
    // =========================================================================

    // See documentation on JobBean#passivate
    @RolesAllowed("user")
    @Transactional(readOnly = true)
    public void passivate() {
        // Nothing necessary
    }

    // See documentation on JobBean#activate
    @RolesAllowed("user")
    @Transactional(readOnly = true)
    public void activate() {
        if (id != null) {
            reset = id;
            id = null;
        }
    }

    @RolesAllowed("user")
    @Transactional(readOnly = false)
    public synchronized Pixels save() {
        if (isModified()) {
            Long id = (pixelsInstance == null) ? null : pixelsInstance.getId();
            if (id == null) {
                return null;
            }

            try {
                byte[] hash = buffer.calculateMessageDigest();
                pixelsInstance.setSha1(Utils.bytesToHex(hash));

            } catch (RuntimeException re) {
                // ticket:3140
                if (re.getCause() instanceof FileNotFoundException) {
                    String msg = "Cannot find path. Deleted? " + buffer;
                    log.warn(msg);
                    clean(); // Prevent a second exception on close.
                    throw new ResourceError(msg);
                }
                throw re;
            } catch (IOException e) {
                log.warn("calculateMessageDigest failed on " + buffer, e);
                throw new ResourceError(e.getMessage());
            }

            iUpdate.flush();
            modified = false;
            return new ShallowCopy().copy(pixelsInstance);
        }
        return null;
    }

    @RolesAllowed("user")
    @Transactional(readOnly = false)
    public void close() {
        try {
            save();
        } catch (RootException root) {
            // ticket:3140
            // if one of our exceptions, then just rethrow
            throw root;
        } catch (RuntimeException re) {
            Long id = (pixelsInstance == null ? null : pixelsInstance.getId());
            log.error("Failed to update pixels: " + id, re);
        } finally {
            clean();
        }
    }

    public void clean() {
        dataService = null;
        pixelsInstance = null;
        try {
            closePixelBuffer();
        } finally {
            buffer = null;
            readBuffer = null;
            pixelsCache = null;
        }
    }

    /**
     * Close the active pixel buffer, cleaning up any potential messes left by
     * the pixel buffer itself.
     */
    private void closePixelBuffer() {
        try {
            if (buffer != null) {
                buffer.close();
            }
        } catch (IOException e) {
            if (log.isDebugEnabled()) {
                log.debug("Buffer could not be closed successfully.", e);
            }
            throw new ResourceError(e.getMessage() + " Please check server log.");
        }
    }

    @RolesAllowed("user")
    public void setPixelsId(long pixelsId, boolean bypassOriginalFile) {
        if (id == null || id.longValue() != pixelsId) {
            id = new Long(pixelsId);
            pixelsInstance = null;
            closePixelBuffer();
            buffer = null;
            reset = null;

            if (pixelsCache != null && pixelsCache.containsKey(pixelsId)) {
                pixelsInstance = pixelsCache.get(pixelsId);
            } else {
                pixelsInstance = iQuery.findByQuery(
                        "select p from Pixels as p " + "join fetch p.pixelsType where p.id = :id",
                        new Parameters().addId(id));
            }

            if (pixelsInstance == null) {
                throw new ValidationException("Cannot read pixels id=" + id);
            }

            try {
                buffer = dataService.getPixelBuffer(pixelsInstance, true);
            } catch (RuntimeException re) {
                // Rolling back to let the next setPixelsId try again
                // since this is most likely our MissingPyramidException.
                // If it's anything more serious, then the instance
                // should most likely be closed.
                id = null;
                throw re;
            }
        }
    }

    @RolesAllowed("user")
    public long getPixelsId() {
        errorIfNotLoaded();

        return id.longValue();
    }

    @RolesAllowed("user")
    public void prepare(Set<Long> pixelsIds) {
        pixelsCache = new ConcurrentHashMap<Long, Pixels>(pixelsIds.size());
        List<Pixels> pixelsList = iQuery.findAllByQuery(
                "select p from Pixels as p join fetch p.pixelsType " + "where p.id in (:ids)",
                new Parameters().addIds(pixelsIds));
        for (Pixels pixels : pixelsList) {
            pixelsCache.put(pixels.getId(), pixels);
        }
    }

    private synchronized void errorIfNotLoaded() {
        // If we're not loaded because of passivation, then load.
        if (reset != null) {
            id = null;
            setPixelsId(reset.longValue(), false);
            reset = null;
        }
        if (buffer == null) {
            throw new ApiUsageException("This RawPixelsStore has not been properly initialized.\n"
                    + "Please set the pixels id before executing any other methods.\n");
        }
    }

    // ~ Delegation
    // =========================================================================

    @RolesAllowed("user")
    public byte[] calculateMessageDigest() {
        errorIfNotLoaded();

        try {
            return buffer.calculateMessageDigest();
        } catch (Exception e) {
            handleException(e);
        }
        return null;
    }

    @RolesAllowed("user")
    public byte[] getHypercube(List<Integer> offset, List<Integer> size, List<Integer> step) {
        errorIfNotLoaded();

        int cubeSize = buffer.getHypercubeSize(offset, size, step);
        if (readBuffer == null || readBuffer.length != cubeSize) {
            readBuffer = new byte[cubeSize];
        }
        try {
            readBuffer = buffer.getHypercubeDirect(offset, size, step, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public byte[] getPlaneRegion(int z, int c, int t, int count, int offset) {
        errorIfNotLoaded();

        int size = buffer.getByteWidth() * count;
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getPlaneRegionDirect(z, c, t, count, offset, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public byte[] getPlane(int arg0, int arg1, int arg2) {
        errorIfNotLoaded();

        int size = buffer.getPlaneSize();
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getPlaneDirect(arg0, arg1, arg2, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public long getPlaneOffset(int arg0, int arg1, int arg2) {
        errorIfNotLoaded();

        try {
            return buffer.getPlaneOffset(arg0, arg1, arg2);
        } catch (Exception e) {
            handleException(e);
        }
        return -1;
    }

    @RolesAllowed("user")
    public int getPlaneSize() {
        errorIfNotLoaded();

        return buffer.getPlaneSize();
    }

    @RolesAllowed("user")
    public byte[] getRegion(int arg0, long arg1) {
        errorIfNotLoaded();

        ByteBuffer region = null;
        try {
            region = buffer.getRegion(arg0, arg1).getData();
        } catch (Exception e) {
            handleException(e);
        }
        return bufferAsByteArrayWithExceptionIfNull(region);
    }

    @RolesAllowed("user")
    public byte[] getRow(int arg0, int arg1, int arg2, int arg3) {
        errorIfNotLoaded();

        int size = buffer.getRowSize();
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getRowDirect(arg0, arg1, arg2, arg3, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public byte[] getCol(int arg0, int arg1, int arg2, int arg3) {
        errorIfNotLoaded();

        int size = buffer.getColSize();
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getColDirect(arg0, arg1, arg2, arg3, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public long getRowOffset(int arg0, int arg1, int arg2, int arg3) {
        errorIfNotLoaded();

        try {
            return buffer.getRowOffset(arg0, arg1, arg2, arg3);
        } catch (Exception e) {
            handleException(e);
        }
        return -1;
    }

    @RolesAllowed("user")
    public int getRowSize() {
        errorIfNotLoaded();

        return buffer.getRowSize();
    }

    @RolesAllowed("user")
    public byte[] getStack(int arg0, int arg1) {
        errorIfNotLoaded();

        int size = buffer.getStackSize();
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getStackDirect(arg0, arg1, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public long getStackOffset(int arg0, int arg1) {
        errorIfNotLoaded();

        try {
            return buffer.getStackOffset(arg0, arg1);
        } catch (Exception e) {
            handleException(e);
        }
        return -1;
    }

    @RolesAllowed("user")
    public int getStackSize() {
        errorIfNotLoaded();

        return buffer.getStackSize();
    }

    @RolesAllowed("user")
    public byte[] getTimepoint(int arg0) {
        errorIfNotLoaded();

        int size = buffer.getTimepointSize();
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getTimepointDirect(arg0, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    @RolesAllowed("user")
    public long getTimepointOffset(int arg0) {
        errorIfNotLoaded();

        try {
            return buffer.getTimepointOffset(arg0);
        } catch (Exception e) {
            handleException(e);
        }
        return -1;
    }

    @RolesAllowed("user")
    public int getTimepointSize() {
        errorIfNotLoaded();

        return buffer.getTimepointSize();
    }

    @RolesAllowed("user")
    public int getTotalSize() {
        errorIfNotLoaded();

        return buffer.getTotalSize();
    }

    @RolesAllowed("user")
    public int getByteWidth() {
        errorIfNotLoaded();

        return buffer.getByteWidth();
    }

    @RolesAllowed("user")
    public boolean isSigned() {
        errorIfNotLoaded();

        return buffer.isSigned();
    }

    @RolesAllowed("user")
    public boolean isFloat() {
        errorIfNotLoaded();

        return buffer.isFloat();
    }

    @RolesAllowed("user")
    public void setPlane(byte[] arg0, int arg1, int arg2, int arg3) {
        errorIfNotLoaded();

        if (diskSpaceChecking) {
            iRepositoryInfo.sanityCheckRepository();
        }

        try {
            buffer.setPlane(arg0, arg1, arg2, arg3);
            modified();
        } catch (Exception e) {
            handleException(e);
        }
    }

    @RolesAllowed("user")
    public void setRegion(int arg0, long arg1, byte[] arg2) {
        errorIfNotLoaded();

        if (diskSpaceChecking) {
            iRepositoryInfo.sanityCheckRepository();
        }

        try {
            buffer.setRegion(arg0, arg1, arg2);
            modified();
        } catch (Exception e) {
            handleException(e);
        }
    }

    @RolesAllowed("user")
    public void setRow(byte[] arg0, int arg1, int arg2, int arg3, int arg4) {
        errorIfNotLoaded();

        if (diskSpaceChecking) {
            iRepositoryInfo.sanityCheckRepository();
        }

        try {
            ByteBuffer buf = ByteBuffer.wrap(arg0);
            buffer.setRow(buf, arg1, arg2, arg3, arg4);
            modified();
        } catch (Exception e) {
            handleException(e);
        }
    }

    @RolesAllowed("user")
    public void setStack(byte[] arg0, int arg1, int arg2, int arg3) {
        errorIfNotLoaded();

        if (diskSpaceChecking) {
            iRepositoryInfo.sanityCheckRepository();
        }

        try {
            buffer.setStack(arg0, arg1, arg2, arg3);
            modified();
        } catch (Exception e) {
            handleException(e);
        }
    }

    @RolesAllowed("user")
    public void setTimepoint(byte[] arg0, int arg1) {
        errorIfNotLoaded();

        if (diskSpaceChecking) {
            iRepositoryInfo.sanityCheckRepository();
        }

        try {
            buffer.setTimepoint(arg0, arg1);
            modified();
        } catch (Exception e) {
            handleException(e);
        }
    }

    // ~ Helpers
    // =========================================================================

    private byte[] bufferAsByteArrayWithExceptionIfNull(ByteBuffer buffer) {
        byte[] b = new byte[buffer.capacity()];
        buffer.get(b, 0, buffer.capacity());
        return b;
    }

    private void handleException(Exception e) {

        if (e instanceof RootException) {
            throw (RootException) e; // Allow our own exceptions.
        }

        if (log.isDebugEnabled()) {
            log.debug("Error handling pixels.", e);
        }

        if (e instanceof IOException) {
            throw new ResourceError(e.getMessage());
        }
        if (e instanceof DimensionsOutOfBoundsException) {
            throw new ApiUsageException(e.getMessage());
        }
        if (e instanceof BufferUnderflowException) {
            throw new ResourceError("BufferUnderflowException: " + e.getMessage());
        }
        if (e instanceof BufferOverflowException) {
            throw new ResourceError("BufferOverflowException: " + e.getMessage());
        }

        // Fallthrough
        if (e instanceof RuntimeException) {
            throw (RuntimeException) e; // No reason to wrap if Runtime
        }
        throw new RuntimeException(e);
    }

    public boolean isDiskSpaceChecking() {
        return diskSpaceChecking;
    }

    public void setDiskSpaceChecking(boolean diskSpaceChecking) {
        this.diskSpaceChecking = diskSpaceChecking;
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#getResolutionLevels()
     */
    @RolesAllowed("user")
    public int getResolutionLevels() {
        return buffer.getResolutionLevels();
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#getTileSize()
     */
    @RolesAllowed("user")
    public int[] getTileSize() {
        errorIfNotLoaded();
        Dimension tileSize = buffer.getTileSize();
        return new int[] { (int) tileSize.getWidth(), (int) tileSize.getHeight() };
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#requiresPixelsPyramid()
     */
    @RolesAllowed("user")
    public boolean requiresPixelsPyramid() {
        errorIfNotLoaded();
        return dataService.requiresPixelsPyramid(pixelsInstance);
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#getResolutionLevel()
     */
    @RolesAllowed("user")
    public int getResolutionLevel() {
        errorIfNotLoaded();
        return buffer.getResolutionLevel();
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#setResolutionLevel(int)
     */
    @RolesAllowed("user")
    public void setResolutionLevel(int resolutionLevel) {
        errorIfNotLoaded();
        buffer.setResolutionLevel(resolutionLevel);
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#getTile(int, int, int, int, int, int, int)
     */
    @RolesAllowed("user")
    public byte[] getTile(int z, int c, int t, int x, int y, int w, int h) {
        errorIfNotLoaded();

        int size = w * h * buffer.getByteWidth();
        if (readBuffer == null || readBuffer.length != size) {
            readBuffer = new byte[size];
        }
        try {
            readBuffer = buffer.getTileDirect(z, c, t, x, y, w, h, readBuffer);
        } catch (Exception e) {
            handleException(e);
        }
        return readBuffer;
    }

    /* (non-Javadoc)
     * @see ome.api.RawPixelsStore#setTile(byte[], int, int, int, int, int, int, int)
     */
    @RolesAllowed("user")
    public void setTile(byte[] data, int z, int c, int t, int x, int y, int w, int h) {
        errorIfNotLoaded();

        if (diskSpaceChecking) {
            iRepositoryInfo.sanityCheckRepository();
        }

        try {
            buffer.setTile(data, z, c, t, x, y, w, h);
            modified();
        } catch (Exception e) {
            handleException(e);
        }
    }

}