Package org.sonatype.nexus.proxy.attributes

Source Code of org.sonatype.nexus.proxy.attributes.DefaultAttributesHandler

/*
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2014 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
*
* This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
* which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software 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.IOException;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.sonatype.nexus.proxy.ResourceStoreRequest;
import org.sonatype.nexus.proxy.access.AccessManager;
import org.sonatype.nexus.proxy.item.ContentLocator;
import org.sonatype.nexus.proxy.item.RepositoryItemUid;
import org.sonatype.nexus.proxy.item.StorageCollectionItem;
import org.sonatype.nexus.proxy.item.StorageFileItem;
import org.sonatype.nexus.proxy.item.StorageItem;
import org.sonatype.nexus.proxy.item.uid.IsMetadataMaintainedAttribute;
import org.sonatype.nexus.proxy.repository.HostedRepository;
import org.sonatype.nexus.proxy.repository.ProxyRepository;
import org.sonatype.nexus.proxy.repository.Repository;
import org.sonatype.nexus.proxy.repository.RepositoryKind;
import org.sonatype.nexus.util.SystemPropertiesHelper;
import org.sonatype.sisu.goodies.common.ComponentSupport;

import static com.google.common.base.Preconditions.checkNotNull;

/**
* The default implementation of AttributesHandler. Does not have any assumption regarding actual AttributeStorage it
* uses. It uses {@link StorageItemInspector} and {@link StorageFileItemInspector} components for "expansion" of core
* (and custom) attributes (those components might come from plugins too). This class also implements some
* "optimizations" for attribute "lastRequested", by using coarser resolution for it (saving it very n-th hour or so).
*
* @author cstamas
*/
@Named
@Singleton
public class DefaultAttributesHandler
    extends ComponentSupport
    implements AttributesHandler
{

  /**
   * Default value of lastRequested attribute updates resolution: 12h
   */
  private static final long LAST_REQUESTED_ATTRIBUTE_RESOLUTION_DEFAULT = 43200000L;

  /**
   * The value of lastRequested attribute updates resolution. Is enforced to be positive long. Setting it to 0 makes
   * Nexus behave in "old" (update always) way.
   */
  private static final long LAST_REQUESTED_ATTRIBUTE_RESOLUTION = Math.abs(SystemPropertiesHelper.getLong(
      "org.sonatype.nexus.proxy.attributes.DefaultAttributesHandler.lastRequested.resolution",
      LAST_REQUESTED_ATTRIBUTE_RESOLUTION_DEFAULT));

  /**
   * Flag to completely enable/disable the lastRequested attribute maintenance.
   */
  private static final boolean LAST_REQUEST_ATTRIBUTE_ENABLED = SystemPropertiesHelper.getBoolean(
      "org.sonatype.nexus.proxy.attributes.DefaultAttributesHandler.lastRequested.enabled", true);

  /**
   * Flag to completely enable/disable the lastRequested attribute maintenance for hosted repositories.
   */
  private static final boolean LAST_REQUEST_ATTRIBUTE_ENABLED_FOR_HOSTED = SystemPropertiesHelper.getBoolean(
      "org.sonatype.nexus.proxy.attributes.DefaultAttributesHandler.lastRequested.enabled.hosted",
      LAST_REQUEST_ATTRIBUTE_ENABLED);

  /**
   * Flag to completely enable/disable the lastRequested attribute maintenance for proxy repositories.
   */
  private static final boolean LAST_REQUEST_ATTRIBUTE_ENABLED_FOR_PROXY = SystemPropertiesHelper.getBoolean(
      "org.sonatype.nexus.proxy.attributes.DefaultAttributesHandler.lastRequested.enabled.proxy",
      LAST_REQUEST_ATTRIBUTE_ENABLED);

  /**
   * The actual value of lastRequest attribute's resolution. Note: is not final due to UT access, see
   * setter method that is visible for testing.
   */
  private long lastRequestedResolution = LAST_REQUESTED_ATTRIBUTE_RESOLUTION;

  /**
   * The attribute storage.
   */
  private final AttributeStorage attributeStorage;

  /**
   * The item inspector list.
   */
  private final List<StorageItemInspector> itemInspectorList;

  @Inject
  public DefaultAttributesHandler(@Named("ls") AttributeStorage attributeStorage,
                                  List<StorageItemInspector> itemInspectorList)
  {
    this.attributeStorage = checkNotNull(attributeStorage);
    this.itemInspectorList = checkNotNull(itemInspectorList);
  }

  // ==

  /**
   * Gets the attribute storage.
   *
   * @return the attribute storage
   */
  public AttributeStorage getAttributeStorage() {
    return attributeStorage;
  }

  /**
   * Gets the item inspector list.
   *
   * @return the item inspector list
   */
  public List<StorageItemInspector> getItemInspectorList() {
    return itemInspectorList;
  }

  // ======================================================================
  // AttributesHandler iface

  @Override
  public boolean deleteAttributes(final RepositoryItemUid uid)
      throws IOException
  {
    if (!isMetadataMaintained(uid)) {
      return false;
    }
    else {
      return getAttributeStorage().deleteAttributes(uid);
    }
  }

  @Override
  public void fetchAttributes(final StorageItem item)
      throws IOException
  {
    if (!isMetadataMaintained(item)) {
      return;
    }

    final Attributes attributes = getAttributeStorage().getAttributes(item.getRepositoryItemUid());

    if (attributes != null) {
      item.getRepositoryItemAttributes().overlayAttributes(attributes);
    }
    else {
      // we are fixing md if we can
      ContentLocator is = null;
      if (item instanceof StorageFileItem &&
          ((StorageFileItem) item).getContentLocator().isReusable()) {
        is = ((StorageFileItem) item).getContentLocator();
      }

      storeAttributes(item, is);
    }
  }

  @Override
  public void storeAttributes(final StorageItem item)
      throws IOException
  {
    if (!isMetadataMaintained(item)) {
      return;
    }

    getAttributeStorage().putAttributes(item.getRepositoryItemUid(), item.getRepositoryItemAttributes());
  }

  @Override
  public void storeAttributes(final StorageItem item, final ContentLocator content)
      throws IOException
  {
    if (!isMetadataMaintained(item)) {
      return;
    }

    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);
    }

    storeAttributes(item);
  }

  @Override
  public void touchItemCheckedRemotely(final long timestamp, final StorageItem storageItem)
      throws IOException
  {
    if (!isMetadataMaintained(storageItem)) {
      return;
    }

    final RepositoryItemUid uid = storageItem.getRepositoryItemUid();
    final Attributes attributes = getAttributeStorage().getAttributes(uid);

    if (attributes != null) {
      attributes.setRepositoryId(uid.getRepository().getId());
      attributes.setPath(uid.getPath());
      attributes.setCheckedRemotely(timestamp);
      attributes.setExpired(false);

      getAttributeStorage().putAttributes(uid, attributes);
    }
  }

  @Override
  public void touchItemLastRequested(final long timestamp, final StorageItem storageItem)
      throws IOException
  {
    if (!isMetadataMaintained(storageItem)) {
      return;
    }

    touchItemLastRequested(timestamp, storageItem.getResourceStoreRequest(), storageItem.getRepositoryItemUid(),
        storageItem.getRepositoryItemAttributes());
  }

  // ======================================================================
  // Internal

  protected boolean isMetadataMaintained(final StorageItem item) {
    if (item instanceof StorageCollectionItem) {
      // not storing attributes of directories
      return false;
    }
    else if (item.isVirtual()) {
      // virtual items have no attributes (nor UID for that matter)
      return false;
    }
    else {
      return isMetadataMaintained(item.getRepositoryItemUid());
    }
  }

  protected boolean isMetadataMaintained(final RepositoryItemUid uid) {
    final Boolean isMetadataMaintained = uid.getAttributeValue(IsMetadataMaintainedAttribute.class);
    if (isMetadataMaintained != null) {
      return isMetadataMaintained.booleanValue();
    }
    else {
      // safest
      return true;
    }
  }

  protected void touchItemLastRequested(final long timestamp, final ResourceStoreRequest request,
                                        final RepositoryItemUid uid, final Attributes attributes)
      throws IOException
  {
    // Touch it only if this is user-originated request (request incoming over HTTP, not a plugin or "internal" one)
    // 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).

    // we do this only for requests originating from REST API (user initiated)
    if (request.getRequestContext().containsKey(AccessManager.REQUEST_REMOTE_ADDRESS)) {
      // if we need to do this at all... user might turn this feature completely off
      if (isTouchLastRequestedEnabled(uid.getRepository())) {
        final long diff = timestamp - attributes.getLastRequested();

        // if timestamp < storageItem.getLastRequested() => diff will be negative => DO THE UPDATE
        // ie. programatically "resetting" lastAccessTime to some past point for whatever reason
        // if timestamp == to storageItem.getLastRequested() => diff will be 0 => SKIP THE UPDATE
        // ie. trying to set to same value, just lessen the needless IO since values are already equal
        // if timestamp > storageItem.getLastRequested() => diff will be positive => DO THE UPDATE IF diff
        // bigger
        // than resolution
        // ie. the "usual" case, obey the resolution then
        if (diff < 0 || ((diff > 0) && (diff > lastRequestedResolution))) {
          attributes.setLastRequested(timestamp);

          getAttributeStorage().putAttributes(uid, attributes);
        }
      }
    }
  }

  protected boolean isTouchLastRequestedEnabled(final Repository repository)
      throws IOException
  {
    // the "default"
    boolean doTouch = LAST_REQUEST_ATTRIBUTE_ENABLED;

    final RepositoryKind repositoryKind = repository.getRepositoryKind();

    if (repositoryKind != null) {
      if (repositoryKind.isFacetAvailable(HostedRepository.class)) {
        // this is a hosted repository
        doTouch = LAST_REQUEST_ATTRIBUTE_ENABLED_FOR_HOSTED;
      }
      else if (repositoryKind.isFacetAvailable(ProxyRepository.class)) {
        // this is a proxy repository
        doTouch = LAST_REQUEST_ATTRIBUTE_ENABLED_FOR_PROXY;
      }
    }

    return doTouch;
  }

  /**
   * Method that expands core (and custom if custom inspector exists, like provided by a plugin) item attributes on
   * files having attributes maintained. This method may be called ONLY if {@link #isMetadataMaintained(StorageItem)}
   * returns {@code true} and the content locator passed in is reusable. Currently this method is invoked only from
   * {@link #storeAttributes(StorageItem, ContentLocator)} method.
   *
   * @param item    the item
   * @param content the reusable content locator
   */
  protected void expandCustomItemAttributes(final StorageItem item, final ContentLocator content) {
    for (StorageItemInspector inspector : getItemInspectorList()) {
      if (inspector.isHandled(item)) {
        try {
          inspector.processStorageItem(item);
        }
        catch (Exception ex) {
          log.warn(
              "Inspector {} throw exception during inspection of {}, continuing...", inspector.getClass(),
              item.getRepositoryItemUid(), ex);
        }
      }
    }
  }

  // ==

}
TOP

Related Classes of org.sonatype.nexus.proxy.attributes.DefaultAttributesHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.