Package ch.entwine.weblounge.contentrepository.impl.endpoint

Source Code of ch.entwine.weblounge.contentrepository.impl.endpoint.ContentRepositoryEndpoint

/*
*  Weblounge: Web Content Management System
*  Copyright (c) 2003 - 2011 The Weblounge Team
*  http://entwinemedia.com/weblounge
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  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 Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software Foundation
*  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package ch.entwine.weblounge.contentrepository.impl.endpoint;

import ch.entwine.weblounge.common.content.MalformedResourceURIException;
import ch.entwine.weblounge.common.content.Resource;
import ch.entwine.weblounge.common.content.ResourceContent;
import ch.entwine.weblounge.common.content.ResourceURI;
import ch.entwine.weblounge.common.content.ResourceUtils;
import ch.entwine.weblounge.common.content.file.FileContent;
import ch.entwine.weblounge.common.impl.content.ResourceURIImpl;
import ch.entwine.weblounge.common.impl.request.RequestUtils;
import ch.entwine.weblounge.common.language.Language;
import ch.entwine.weblounge.common.repository.ContentRepository;
import ch.entwine.weblounge.common.repository.ContentRepositoryException;
import ch.entwine.weblounge.common.repository.WritableContentRepository;
import ch.entwine.weblounge.common.site.Site;
import ch.entwine.weblounge.common.url.UrlUtils;
import ch.entwine.weblounge.kernel.site.SiteManager;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.StreamingOutput;

/**
* Utility implementation for content repository endpoints, providing easy
* access to the content repository and its functionality.
*/
public class ContentRepositoryEndpoint {

  /** Logging facility */
  static final Logger logger = LoggerFactory.getLogger(ContentRepositoryEndpoint.class);

  /** Regular expression to match the resource type */
  protected static final Pattern resourceTypeRegex = Pattern.compile("<([a-z]*)\\s");

  /** The sites that are online */
  protected transient SiteManager sites = null;

  /**
   * Loads the given resource content.
   *
   * @param request
   *          the servlet request
   * @param resource
   *          the resource
   * @param language
   *          the language
   * @return the resource content
   */
  protected Response getResourceContent(HttpServletRequest request,
      final Resource<?> resource, final Language language) {

    // Check the parameters
    if (resource == null)
      throw new WebApplicationException(Status.BAD_REQUEST);

    // Is there an up-to-date, cached version on the client side?
    if (!ResourceUtils.hasChanged(request, resource, language)) {
      return Response.notModified().build();
    }

    // Load the content
    ResourceContent resourceContent = resource.getContent(language);
    if (resourceContent == null) {
      throw new WebApplicationException(Status.NOT_FOUND);
    }

    // If the content is hosted externally, send a redirect and be done with it
    if (resourceContent.getExternalLocation() != null) {
      try {
        return Response.temporaryRedirect(resourceContent.getExternalLocation().toURI()).build();
      } catch (URISyntaxException e) {
        throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
      }
    }

    Site site = getSite(request);
    final ContentRepository contentRepository = getContentRepository(site, false);

    // Create the response
    final InputStream is;
    try {
      is = contentRepository.getContent(resource.getURI(), language);
    } catch (IOException e) {
      throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
    } catch (ContentRepositoryException e) {
      throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
    }

    // Is the content locally available
    if (is == null)
      throw new WebApplicationException(Status.NOT_FOUND);

    // Write the file contents back
    ResponseBuilder response = Response.ok(new StreamingOutput() {
      public void write(OutputStream os) throws IOException,
          WebApplicationException {
        try {
          IOUtils.copy(is, os);
        } catch (IOException e) {
          if (!RequestUtils.isCausedByClient(e))
            logger.warn("Error writing file contents to response", e);
        } finally {
          IOUtils.closeQuietly(is);
          IOUtils.closeQuietly(os);
        }
      }
    });

    // Set file-related response information
    if (resourceContent instanceof FileContent) {
      FileContent fileContent = (FileContent) resourceContent;
      if (fileContent.getMimetype() != null)
        response.type(fileContent.getMimetype());
      else
        response.type(MediaType.APPLICATION_OCTET_STREAM);
      if (fileContent.getSize() > 0)
        response.header("Content-Length", fileContent.getSize());
    }

    // Add an e-tag and send the response
    response.header("Content-Disposition", "inline; filename=" + resource.getContent(language).getFilename());
    response.tag(ResourceUtils.getETagValue(resource));
    response.lastModified(ResourceUtils.getModificationDate(resource, language));
    return response.build();
  }

  /**
   * Returns the resource identified by the given request and resource
   * identifier or <code>null</code> if either one of the site, the site's
   * content repository or the resource itself is not available.
   * <p>
   * If <code>resourceType</code> is not <code>null</code>, the loaded resource
   * is only returned if the resource type matches.
   *
   * @param request
   *          the servlet request
   * @param resourceId
   *          the resource identifier
   * @param resourceType
   *          the resource type
   * @return the resource
   */
  protected Resource<?> loadResource(HttpServletRequest request,
      String resourceId, String resourceType) {
    return loadResource(request, resourceId, resourceType, Resource.LIVE);
  }

  /**
   * Returns the resource identified by the given request and resource
   * identifier or <code>null</code> if either one of the site, the site's
   * content repository or the resource itself is not available.
   * <p>
   * If <code>resourceType</code> is not <code>null</code>, the loaded resource
   * is only returned if the resource type matches.
   *
   * @param request
   *          the servlet request
   * @param resourceId
   *          the resource identifier
   * @param resourceType
   *          the resource type
   * @param version
   *          the version
   * @return the resource
   */
  protected Resource<?> loadResource(HttpServletRequest request,
      String resourceId, String resourceType, long version) {
    if (sites == null) {
      logger.debug("Unable to load resource '{}': no sites registered", resourceId);
      return null;
    }

    // Extract the site
    Site site = getSite(request);

    // Look for the content repository
    ContentRepository contentRepository = site.getContentRepository();
    if (contentRepository == null) {
      logger.warn("No content repository found for site '{}'", site);
      throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
    }

    // Load the resource and return it
    try {
      ResourceURI resourceURI = new ResourceURIImpl(resourceType, site, null, resourceId, version);
      Resource<?> resource = contentRepository.get(resourceURI);
      if (resource == null)
        return null;
      if (resourceType != null && !resourceType.equals(resource.getURI().getType())) {
        return null;
      }
      return resource;
    } catch (ContentRepositoryException e) {
      throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Returns the resource identified by the given request and resource path or
   * <code>null</code> if either one of the site, the site's content repository
   * or the resource itself is not available.
   * <p>
   * If <code>resourceType</code> is not <code>null</code>, the loaded resource
   * is only returned if the resource type matches.
   *
   * @param request
   *          the servlet request
   * @param resourcePath
   *          the resource path
   * @param resourceType
   *          the resource type
   * @return the resource
   */
  protected Resource<?> loadResourceByPath(HttpServletRequest request,
      String resourcePath, String resourceType) {
    if (sites == null) {
      logger.debug("Unable to load resource '{}': no sites registered", resourcePath);
      return null;
    }

    // Extract the site
    Site site = getSite(request);

    // Look for the content repository
    ContentRepository contentRepository = site.getContentRepository();
    if (contentRepository == null) {
      logger.warn("No content repository found for site '{}'", site);
      throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
    }

    // Load the resource and return it
    try {
      ResourceURI resourceURI = new ResourceURIImpl(resourceType, site, resourcePath);
      Resource<?> resource = contentRepository.get(resourceURI);
      if (resource == null)
        return null;
      if (resourceType != null && !resourceType.equals(resource.getURI().getType())) {
        return null;
      }
      return resource;
    } catch (MalformedResourceURIException e) {
      throw new WebApplicationException(Status.BAD_REQUEST);
    } catch (ContentRepositoryException e) {
      throw new WebApplicationException(Status.INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Tries to locate the content repository for the given site. If
   * <code>writable</code> is <code>true</code>, the method tries to cast the
   * repository to a <code>WritableContentRepository</code>.
   * <p>
   * This method throws a corresponding <code>WebApplicationException</code> in
   * case of failure.
   *
   * @param site
   *          the site
   * @param writable
   *          <code>true</code> to request a writable repository
   * @return the repository
   * @throws WebApplicationException
   *           if the repository can't be located or if it's not writable
   */
  protected ContentRepository getContentRepository(Site site, boolean writable) {
    try {
      ContentRepository contentRepository = site.getContentRepository();

      // Make sure the content repository is ready to use
      if (contentRepository == null) {
        logger.debug("No content repository found for site '{}'", site);
        throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
      } else if (contentRepository.isIndexing()) {
        logger.debug("Content repository is being indexed '{}'", site);
        throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
      }

      // Is the client asking for a writable repository?
      if (writable) {
        if (contentRepository.isReadOnly()) {
          logger.warn("Content repository '{}' is not writable", site);
          throw new WebApplicationException(Status.PRECONDITION_FAILED);
        }
        WritableContentRepository wcr = (WritableContentRepository) contentRepository;
        return wcr;
      } else {
        return contentRepository;
      }

    } catch (ClassCastException e) {
      logger.warn("Content repository '{}' is not writable", site);
      throw new WebApplicationException(Status.PRECONDITION_FAILED);
    }
  }

  /**
   * Extracts the site from the request and returns it. If the site is not found
   * or it's not running, a corresponding <code>WebApplicationException</code>
   * is thrown.
   *
   * @param request
   *          the http request
   * @return the site
   * @throws WebApplicationException
   *           if the site is not found or is not running
   */
  protected Site getSite(HttpServletRequest request)
      throws WebApplicationException {
    URL url = UrlUtils.toURL(request, false, false);
    Site site = sites.findSiteByURL(url);
    if (site == null) {
      throw new WebApplicationException(Status.NOT_FOUND);
    } else if (!site.isOnline()) {
      throw new WebApplicationException(Status.SERVICE_UNAVAILABLE);
    }
    return site;
  }

  /**
   * Returns the resource type or <code>null</code> if the type could not be
   * extracted from the specified document.
   *
   * @param input
   *          the input text
   * @return the resource type
   */
  protected String getResourceType(String input) {
    Matcher m = resourceTypeRegex.matcher(input);
    if (m.find()) {
      return m.group(1);
    }
    return null;
  }

  /**
   * Callback for OSGi to set the site manager.
   *
   * @param siteManager
   *          the site manager
   */
  void setSiteManager(SiteManager siteManager) {
    this.sites = siteManager;
  }

}
TOP

Related Classes of ch.entwine.weblounge.contentrepository.impl.endpoint.ContentRepositoryEndpoint

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.