/**
* Copyright (c) 2008-2011 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
*
* This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
* Public License Version 3 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License Version 3
* for more details.
*
* You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see
* http://www.gnu.org/licenses.
*
* Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
* Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
* All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.proxy.attributes;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.IOUtil;
import org.sonatype.nexus.configuration.application.ApplicationConfiguration;
import org.sonatype.nexus.proxy.ItemNotFoundException;
import org.sonatype.nexus.proxy.LocalStorageException;
import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.access.AccessManager;
import org.sonatype.nexus.proxy.item.AbstractStorageItem;
import org.sonatype.nexus.proxy.item.ContentLocator;
import org.sonatype.nexus.proxy.item.RepositoryItemUid;
import org.sonatype.nexus.proxy.item.StorageFileItem;
import org.sonatype.nexus.proxy.item.StorageItem;
import org.sonatype.nexus.proxy.repository.Repository;
import org.sonatype.nexus.proxy.storage.local.fs.FileContentLocator;
/**
* The Class DefaultAttributesHandler.
*
* @author cstamas
*/
@Component( role = AttributesHandler.class )
public class DefaultAttributesHandler
implements AttributesHandler
{
@Requirement
private Logger logger;
/**
* The application configuration.
*/
@Requirement
private ApplicationConfiguration applicationConfiguration;
/**
* The attribute storage.
*/
@Requirement
private AttributeStorage attributeStorage;
/**
* The item inspector list.
*/
@Requirement( role = StorageItemInspector.class )
protected List<StorageItemInspector> itemInspectorList;
/**
* The item inspector list.
*/
@Requirement( role = StorageFileItemInspector.class )
protected List<StorageFileItemInspector> fileItemInspectorList;
// ==
protected Logger getLogger()
{
return logger;
}
/**
* Gets the attribute storage.
*
* @return the attribute storage
*/
public AttributeStorage getAttributeStorage()
{
return attributeStorage;
}
/**
* Sets the attribute storage.
*
* @param attributeStorage the new attribute storage
*/
public void setAttributeStorage( AttributeStorage attributeStorage )
{
this.attributeStorage = attributeStorage;
}
/**
* Gets the item inspector list.
*
* @return the item inspector list
*/
public List<StorageItemInspector> getItemInspectorList()
{
return itemInspectorList;
}
/**
* Sets the item inspector list.
*
* @param itemInspectorList the new item inspector list
*/
public void setItemInspectorList( List<StorageItemInspector> itemInspectorList )
{
this.itemInspectorList = itemInspectorList;
}
/**
* Gets the file item inspector list.
*
* @return the file item inspector list
*/
public List<StorageFileItemInspector> getFileItemInspectorList()
{
return fileItemInspectorList;
}
/**
* Sets the file item inspector list.
*
* @param fileItemInspectorList the new file item inspector list
*/
public void setFileItemInspectorList( List<StorageFileItemInspector> fileItemInspectorList )
{
this.fileItemInspectorList = fileItemInspectorList;
}
// ======================================================================
// AttributesHandler iface
public boolean deleteAttributes( RepositoryItemUid uid )
{
return getAttributeStorage().deleteAttributes( uid );
}
public void fetchAttributes( StorageItem item )
{
StorageItem mdItem = getAttributeStorage().getAttributes( item.getRepositoryItemUid() );
if ( mdItem != null )
{
item.overlay( mdItem );
}
else
{
// we are fixing md if we can
ContentLocator is = null;
if ( StorageFileItem.class.isAssignableFrom( item.getClass() ) )
{
if ( ( (StorageFileItem) item ).getContentLocator().isReusable() )
{
is = ( (StorageFileItem) item ).getContentLocator();
}
}
storeAttributes( item, is );
}
}
public void storeAttributes( final StorageItem item, final ContentLocator content )
{
if ( content != null )
{
// resetting some important values
if ( item.getRemoteChecked() == 0 )
{
item.setRemoteChecked( System.currentTimeMillis() );
}
if ( item.getLastRequested() == 0 )
{
item.setLastRequested( System.currentTimeMillis() );
}
item.setExpired( false );
// resetting the pluggable attributes
expandCustomItemAttributes( item, content );
}
getAttributeStorage().putAttribute( item );
}
// ==
public void touchItemRemoteChecked( Repository repository, ResourceStoreRequest request )
throws ItemNotFoundException, LocalStorageException
{
touchItemRemoteChecked( System.currentTimeMillis(), repository, request );
}
public void touchItemRemoteChecked( long timestamp, Repository repository, ResourceStoreRequest request )
throws ItemNotFoundException, LocalStorageException
{
RepositoryItemUid uid = repository.createUid( request.getRequestPath() );
AbstractStorageItem item = getAttributeStorage().getAttributes( uid );
if ( item != null )
{
item.setResourceStoreRequest( request );
item.setRepositoryItemUid( uid );
item.setRemoteChecked( timestamp );
item.setExpired( false );
getAttributeStorage().putAttribute( item );
}
}
public void touchItemLastRequested( Repository repository, ResourceStoreRequest request )
throws ItemNotFoundException, LocalStorageException
{
touchItemLastRequested( System.currentTimeMillis(), repository, request );
}
public void touchItemLastRequested( long timestamp, Repository repository, ResourceStoreRequest request )
throws ItemNotFoundException, LocalStorageException
{
RepositoryItemUid uid = repository.createUid( request.getRequestPath() );
AbstractStorageItem item = getAttributeStorage().getAttributes( uid );
if ( item != null )
{
item.setResourceStoreRequest( request );
item.setRepositoryItemUid( uid );
touchItemLastRequested( timestamp, repository, request, item );
}
}
public void touchItemLastRequested( long timestamp, Repository repository, ResourceStoreRequest request,
StorageItem storageItem )
throws ItemNotFoundException, LocalStorageException
{
// TODO: touch it only if this is user-originated request
// Currently, we test for IP address presence, since that makes sure it is user request (from REST API) and not
// a request from "internals" (ie. a running task).
if ( request.getRequestContext().containsKey( AccessManager.REQUEST_REMOTE_ADDRESS ) )
{
storageItem.setLastRequested( timestamp );
getAttributeStorage().putAttribute( storageItem );
}
}
public void updateItemAttributes( Repository repository, ResourceStoreRequest request, StorageItem item )
throws ItemNotFoundException, LocalStorageException
{
getAttributeStorage().putAttribute( item );
}
// ======================================================================
// Internal
/**
* Expand custom item attributes.
*
* @param item the item
* @param inputStream the input stream
*/
protected void expandCustomItemAttributes( StorageItem item, ContentLocator content )
{
// gather inspectors willing to participate first, to save file copying below
ArrayList<StorageFileItemInspector> handlingInspectors = new ArrayList<StorageFileItemInspector>();
for ( StorageFileItemInspector inspector : getFileItemInspectorList() )
{
if ( inspector.isHandled( item ) )
{
handlingInspectors.add( inspector );
}
}
if ( handlingInspectors.isEmpty() )
{
return;
}
boolean deleteTmpFile = false;
File tmpFile = null;
if ( content != null )
{
if ( content instanceof FileContentLocator )
{
deleteTmpFile = false;
tmpFile = ( (FileContentLocator) content ).getFile();
}
else
{
getLogger().info(
"Doing a temporary copy of the \""
+ item.getPath()
+ "\" item's content for expanding custom attributes. This should NOT happen, but is left in as \"fallback\"!" );
deleteTmpFile = true;
try
{
InputStream inputStream = null;
OutputStream tmpFileStream = null;
try
{
// unpack the file
tmpFile =
File.createTempFile( "px-" + item.getName(), ".tmp",
applicationConfiguration.getTemporaryDirectory() );
inputStream = content.getContent();
tmpFileStream = new FileOutputStream( tmpFile );
IOUtils.copy( inputStream, tmpFileStream );
tmpFileStream.flush();
tmpFileStream.close();
}
finally
{
IOUtil.close( inputStream );
IOUtil.close( tmpFileStream );
}
}
catch ( IOException ex )
{
getLogger().warn( "Could not create file from " + item.getRepositoryItemUid(), ex );
tmpFile = null;
}
}
}
if ( StorageFileItem.class.isAssignableFrom( item.getClass() ) )
{
StorageFileItem fItem = (StorageFileItem) item;
if ( !fItem.isVirtual() && tmpFile != null )
{
try
{
// we should prepare a file for inspectors
for ( StorageFileItemInspector inspector : handlingInspectors )
{
if ( inspector.isHandled( item ) )
{
try
{
inspector.processStorageFileItem( fItem, tmpFile );
}
catch ( Exception ex )
{
getLogger().warn(
"Inspector " + inspector.getClass() + " throw exception during inspection of "
+ item.getRepositoryItemUid() + ", continuing...", ex );
}
}
}
}
finally
{
if ( deleteTmpFile && tmpFile != null )
{
tmpFile.delete();
}
tmpFile = null;
}
}
}
else
{
for ( StorageItemInspector inspector : getItemInspectorList() )
{
if ( inspector.isHandled( item ) )
{
try
{
inspector.processStorageItem( item );
}
catch ( Exception ex )
{
getLogger().warn(
"Inspector " + inspector.getClass() + " throw exception during inspection of "
+ item.getRepositoryItemUid() + ", continuing...", ex );
}
}
}
}
// result.setDate( LocalStorageItem.LOCAL_ITEM_LAST_INSPECTED_KEY, new Date() );
}
}