supportedMimetypes, double reliability, long extractionTime)
    {
        this.supportedMimetypes = supportedMimetypes;
        this.reliability = reliability;
        this.extractionTime = extractionTime;
    }
    /**
     * Set the registry to register with
     * 
     * @param registry a metadata extracter registry
     */
    public void setRegistry(MetadataExtracterRegistry registry)
    {
        this.registry = registry;
    }
    /**
     * Helper setter of the mimetype service.  This is not always required.
     * 
     * @param mimetypeService
     */
    public void setMimetypeService(MimetypeService mimetypeService)
    {
        this.mimetypeService = mimetypeService;
    }
    /**
     * @return Returns the mimetype helper
     */
    protected MimetypeService getMimetypeService()
    {
        return mimetypeService;
    }
    
    /**
     * Registers this instance of the extracter with the registry.
     * 
     * @see #setRegistry(MetadataExtracterRegistry)
     */
    public void register()
    {
        if (registry == null)
        {
            logger.warn("Property 'registry' has not been set.  Ignoring auto-registration: \n" +
                    "   extracter: " + this);
            return;
        }
        registry.register(this);
    }
    
    /**
     * Default reliability check that returns the reliability as configured by the contstructor
     * if the mimetype is in the list of supported mimetypes.
     * 
     * @param mimetype the mimetype to check
     */
    public double getReliability(String mimetype)
    {
        if (supportedMimetypes.contains(mimetype))
            return reliability;
        else
            return 0.0;
    }
    /**
     * {@inheritDoc}
     * 
     * @return      Returns true if the {@link #getReliability(String) reliability}
     *              is greater than 0
     */
    public boolean isSupported(String mimetype)
    {
        double reliability = getReliability(mimetype);
        return reliability > 0.0;
    }
    public long getExtractionTime()
    {
        return extractionTime;
    }
    
    /**
     * Checks if the mimetype is supported.
     * 
     * @param reader the reader to check
     * @throws AlfrescoRuntimeException if the mimetype is not supported
     */
    protected void checkReliability(ContentReader reader)
    {
        String mimetype = reader.getMimetype();
        if (getReliability(mimetype) <= 0.0)
        {
            throw new AlfrescoRuntimeException(
                    "Metadata extracter does not support mimetype: \n" +
                    "   reader: " + reader + "\n" +
                    "   supported: " + supportedMimetypes + "\n" +
                    "   extracter: " + this);
        }
    }
    /**
     * {@inheritDoc}
     * 
     * A {@linkplain OverwritePolicy#PRAGMATIC pragmatic} overwrite policy will be applied.
     */
    public Map extract(ContentReader reader, Map destination)
    {
        return extract(reader, OverwritePolicy.PRAGMATIC, destination);
    }
    /**
     * {@inheritDoc}
     * 
     * @param propertyMapping       ignored
     * 
     * @see #extract(ContentReader, Map)
     */
    public final Map extract(
            ContentReader reader,
            OverwritePolicy overwritePolicy,
            Map destination) throws ContentIOException
    {
        // check the reliability
        checkReliability(reader);
        
        Map newProperties = new HashMap(13);
        try
        {
            extractInternal(reader, newProperties);
            // Apply the overwrite policy
            Map modifiedProperties = overwritePolicy.applyProperties(newProperties, destination);
            // done
            if (logger.isDebugEnabled())
            {
                logger.debug("Completed metadata extraction: \n" +
                        "   reader: " + reader + "\n" +
                        "   extracter: " + this);
            }
            return modifiedProperties;
        }
        catch (Throwable e)
        {
            throw new ContentIOException("Metadata extraction failed: \n" +
                    "   reader: " + reader,
                    e);
        }
        finally
        {
            // check that the reader was closed (if used)
            if (reader.isChannelOpen())
            {
                logger.error("Content reader not closed by metadata extracter: \n" +
                        "   reader: " + reader + "\n" +
                        "   extracter: " + this);
            }
        }
    }
    /**
     * {@inheritDoc}
     * 
     * @param overwritePolicy       ignored
     * @param propertyMapping       ignored
     * 
     * @see #extract(ContentReader, Map)
     */
    public final Map extract(
            ContentReader reader,
            OverwritePolicy overwritePolicy,
            Map destination,
            Map> propertyMapping) throws ContentIOException
    {
        return extract(reader, destination);
    }
    /**
     * Override to provide the necessary extraction logic.  Implementations must ensure that the reader
     * is closed before the method exits.
     * 
     * @param reader the source of the content
     * @param destination the property map to fill
     * @throws Throwable an exception
     * 
     * @deprecated      Consider deriving from the more configurable {@link AbstractMappingMetadataExtracter}
     */
    protected abstract void extractInternal(ContentReader reader, Map destination) throws Throwable;
    
    /**
     * Examines a value or string for nulls and adds it to the map (if non-empty)
     * 
     * @param prop Alfresco's ContentModel.PROP_ to set.
     * @param value Value to set it to
     * @param destination Map into which to set it
     * @return true, if set, false otherwise
     */
    protected boolean trimPut(QName prop, Object value, Map destination)
    {
        if (value == null)
            return false;
        if (value instanceof String)
        {
            String svalue = ((String) value).trim();
            if (svalue.length() > 0)
            {
                destination.put(prop, svalue);
                return true;
            }
            return false;
        }
        else if (value instanceof Serializable)
        {
            destination.put(prop, (Serializable) value);
        }
        else
        {
            destination.put(prop, value.toString());
        }
        return true;
    }
}