Package com.dotmarketing.servlets

Source Code of com.dotmarketing.servlets.BinaryExporterServlet

package com.dotmarketing.servlets;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.dotcms.repackage.org.apache.commons.collections.LRUMap;
import com.dotmarketing.beans.Identifier;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.DotStateException;
import com.dotmarketing.business.PermissionAPI;
import com.dotmarketing.business.UserAPI;
import com.dotmarketing.business.web.UserWebAPI;
import com.dotmarketing.business.web.WebAPILocator;
import com.dotmarketing.cache.LiveCache;
import com.dotmarketing.cache.WorkingCache;
import com.dotmarketing.cms.factories.PublicEncryptionFactory;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotHibernateException;
import com.dotmarketing.exception.DotRuntimeException;
import com.dotmarketing.exception.DotSecurityException;
import com.dotmarketing.portlets.contentlet.business.BinaryContentExporter;
import com.dotmarketing.portlets.contentlet.business.BinaryContentExporterException;
import com.dotmarketing.portlets.contentlet.business.ContentletAPI;
import com.dotmarketing.portlets.contentlet.business.DotContentletStateException;
import com.dotmarketing.portlets.contentlet.model.Contentlet;
import com.dotmarketing.portlets.fileassets.business.IFileAsset;
import com.dotmarketing.portlets.files.business.FileAPI;
import com.dotmarketing.portlets.structure.model.Field;
import com.dotmarketing.util.Config;
import com.dotmarketing.util.Constants;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.dotmarketing.util.WebKeys;
import com.liferay.portal.PortalException;
import com.liferay.portal.SystemException;
import com.liferay.portal.model.User;
import com.liferay.util.FileUtil;

/**
*
* This servlet allows you invoke content exporters over binary fields.
* With the following URL syntax you are able to invoke an specific content exporter on a piece of content.
*
* /contentAsset/{exporter path}/{content identifier}/{binary field - optional}?{byInode=true&}{exporter specific parameters}
*
* {exporter path} is the exporter specific path set by the exporter class. I.E. every exporter must implement an interface method call getPathMapping that
* defines the path of what the exporter is going to be bound. E.G. The com.dotmarketing.portlets.contentlet.business.exporter.ImageResizeFieldExporter binds
* to the resize-image path so it can be invoked as /contentAsset/resize-image/...
*
* {content identifier} is the identifier of the piece of content that wants to be retrieved. Special case occurs when the url parameter "byInode=true" is set
* then the content specific inode must be passed here.
*
* {binary field - optional} is the binary field velocity name (refer to the structure manager to fidn out which is your field velocity name). This url part could be
* obeyed for certain exporters that operate over the entire content instead of an specific field like with an XML content exporter for example.
*
* {exporter specific parameters} is for exporter specific parameters, refer to the exporter documentation. Exporters like the thubmnail generator takes parameters
* like the width or height of the thumbnail to be generated.
*
* @author David Torres 2010
*
*/
public class BinaryExporterServlet extends HttpServlet {

  private static final FileAPI fileAPI = APILocator.getFileAPI();
  private static final UserAPI userAPI = APILocator.getUserAPI();
  Map<String, BinaryContentExporter> exportersByPathMapping;
  private static String assetPath = "/assets";
  private static String realPath = null;

  @SuppressWarnings("unchecked")
  @Override
  public void init() throws ServletException {
    super.init();
        if(UtilMethods.isSet(Config.getStringProperty("ASSET_REAL_PATH"))){
            realPath = Config.getStringProperty("ASSET_REAL_PATH");
        }
        if(UtilMethods.isSet(Config.getStringProperty("ASSET_PATH"))){
            assetPath = Config.getStringProperty("ASSET_PATH");
        }
    exportersByPathMapping = new HashMap<String, BinaryContentExporter>();

    Iterator<String> keys = Config.getKeys();

    while(keys.hasNext()) {
      String key = keys.next();
      if(key.startsWith("CONTENT_EXPORTERS")) {
        String[]  exporterClasses = Config.getStringArrayProperty(key);
        for(String exporterClassName : exporterClasses) {
          try {
            Class<BinaryContentExporter> exporterClass = (Class<BinaryContentExporter>) Class.forName(exporterClassName);
            BinaryContentExporter exporter = exporterClass.newInstance();
            if(exportersByPathMapping.containsKey(exporter.getPathMapping()))
              Logger.warn(BinaryExporterServlet.class, "There is already an exporter registered to path " + exporter.getPathMapping() +
                  " this new exporter: " + exporter.getName() + " will replace the previously registered: " +
                  exportersByPathMapping.get(exporter.getPathMapping()).getName());

            Logger.info(this, "Exporter \"" + exporter.getName() + "\" registered for path /" + exporter.getPathMapping());
            exportersByPathMapping.put(exporter.getPathMapping(), exporter);

          } catch (ClassNotFoundException e) {
            Logger.warn(BinaryExporterServlet.class, e.getMessage(), e);
          } catch (InstantiationException e) {
            Logger.warn(BinaryExporterServlet.class, e.getMessage(), e);
          } catch (IllegalAccessException e) {
            Logger.warn(BinaryExporterServlet.class, e.getMessage(), e);
          }
        }
      }
    }
  }

  private static final long serialVersionUID = 1L;

  @SuppressWarnings("unchecked")
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String servletPath = req.getServletPath();
    String uri = req.getRequestURI().substring(servletPath.length());
    String[] uriPieces = uri.split("/");
    String exporterPath = uriPieces[1];
    String uuid = uriPieces[2];

    Map<String, String[]> params = new HashMap<String, String[]>();
    params.putAll(req.getParameterMap());
    // only set uri params if they are not set in the query string - meaning
    // the query string will override the uri params.
    Map<String, String[]> uriParams = getURIParams(req);
    for(String x: uriParams.keySet()){
      if(!params.containsKey(x)){
        params.put(x, uriParams.get(x));
      }
    }
    params = sortByKey(params);

    String assetInode = null;
    String assetIdentifier = null;
    boolean byInode = params.containsKey("byInode") ;
    if (byInode){
      assetInode = uuid;
    }
    else{
      assetIdentifier = uuid;
    }

    String fieldVarName = uriPieces.length > 3?uriPieces[3]:null;
    BinaryContentExporter exporter = exportersByPathMapping.get(exporterPath);
    if(exporter == null) {
      Logger.warn(this, "No exporter for path " + exporterPath + " is registered. Requested url = " + uri);
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
      return;
    }

    UserWebAPI userWebAPI = WebAPILocator.getUserWebAPI();
    ContentletAPI contentAPI = APILocator.getContentletAPI();
    BinaryContentExporter.BinaryContentExporterData data = null;
    File inputFile = null;
    HttpSession session = req.getSession(false);
    List<String> tempBinaryImageInodes = null;
        if ( session != null && session.getAttribute( Contentlet.TEMP_BINARY_IMAGE_INODES_LIST ) != null ) {
            tempBinaryImageInodes = (List<String>) session.getAttribute( Contentlet.TEMP_BINARY_IMAGE_INODES_LIST );
        } else {
            tempBinaryImageInodes = new ArrayList<String>();
        }

        boolean isTempBinaryImage = tempBinaryImageInodes.contains(assetInode);
    try {
      User user = userWebAPI.getLoggedInUser(req);
      boolean respectFrontendRoles = !userWebAPI.isLoggedToBackend(req);
      String downloadName = "file_asset";
      long lang = APILocator.getLanguageAPI().getDefaultLanguage().getId();
      try {
        String x = null;
        if (session != null) {
          x = (String) session.getAttribute(WebKeys.HTMLPAGE_LANGUAGE);
        } else {
          x = (String) req.getAttribute(WebKeys.HTMLPAGE_LANGUAGE);
        }
        lang = Long.parseLong(x);
      } catch(Exception e){
        // Number parsing exception
      }

      boolean isContent = false;
      try {
        isContent = isContent(uuid, byInode, lang, respectFrontendRoles);
      }catch (DotStateException e) {
        resp.sendError(404);
        return;
      }

      if (isContent){
        Contentlet content = null;
        if(byInode) {
          if(isTempBinaryImage)
            content = contentAPI.find(assetInode, APILocator.getUserAPI().getSystemUser(), respectFrontendRoles);
          else
            content = contentAPI.find(assetInode, user, respectFrontendRoles);
          assetIdentifier = content.getIdentifier();
        } else {
            boolean live=userWebAPI.isLoggedToFrontend(req);
            if (req.getSession(false) != null && req.getSession().getAttribute("tm_date")!=null) {
                live=true;
                Identifier ident=APILocator.getIdentifierAPI().find(assetIdentifier);
                if(UtilMethods.isSet(ident.getSysPublishDate()) || UtilMethods.isSet(ident.getSysExpireDate())) {
                    Date fdate=new Date(Long.parseLong((String)req.getSession().getAttribute("tm_date")));
                    if(UtilMethods.isSet(ident.getSysPublishDate()) && ident.getSysPublishDate().before(fdate))
                        live=false;
                    if(UtilMethods.isSet(ident.getSysExpireDate()) && ident.getSysExpireDate().before(fdate))
                        return; // expired!
                }
            }
          content = contentAPI.findContentletByIdentifier(assetIdentifier, live, lang, user, respectFrontendRoles);
          assetInode = content.getInode();
        }
        Field field = content.getStructure().getFieldVar(fieldVarName);
        if(field == null){
          Logger.debug(this,"Field " + fieldVarName + " does not exists within structure " + content.getStructure().getVelocityVarName());
          resp.sendError(404);
          return;
        }

        if(isTempBinaryImage)
          inputFile = contentAPI.getBinaryFile(content.getInode(), field.getVelocityVarName(), APILocator.getUserAPI().getSystemUser());
        else
          inputFile = contentAPI.getBinaryFile(content.getInode(), field.getVelocityVarName(), user);
        if(inputFile == null){
          Logger.debug(this,"binary file '" + fieldVarName + "' does not exist for inode " + content.getInode());
          resp.sendError(404);
          return;
        }
        downloadName = inputFile.getName();
      }
      else{
        // if we are using this as a "Save as" from the image too
        fieldVarName = WebKeys.EDITED_IMAGE_FILE_ASSET;
        com.dotmarketing.portlets.files.model.File dotFile = null;

        // get the identifier from cache
        if(byInode) {
          dotFile = fileAPI.find(assetInode,user,false);
          downloadName = dotFile.getFileName();
          //com.dotmarketing.portlets.files.model.File dotFile = APILocator.getFileAPI().get(assetIdentifier, user, respectFrontendRoles);
          assetIdentifier = dotFile.getIdentifier();
        }
        Identifier id = APILocator.getIdentifierAPI().find(assetIdentifier);

        // no identifier, no soup!
        if(id == null || ! UtilMethods.isSet(id.getInode())){
          Logger.debug(this,"Identifier: " + assetIdentifier +"not found");
          resp.sendError(404);
          return;
        }

        boolean hasLive = (LiveCache.getPathFromCache(id.getURI(), id.getHostId()) != null);
        // no live version and front end, no soup
        if(respectFrontendRoles && ! hasLive){
          Logger.debug(this,"File :" + id.getInode() +"is not live");
          resp.sendError(404);
          return;
        }
        // no permissions, no soup!
        if(!APILocator.getPermissionAPI().doesUserHavePermission(id, PermissionAPI.PERMISSION_READ, user)){
          Logger.debug(this,"user: " + user + " does not have read on File :" + id.getInode());
          if(WebAPILocator.getUserWebAPI().isLoggedToFrontend(req)){
            resp.sendError(403);
          }else{
            resp.sendError(401);
          }
          return;
        }

        if(assetInode != null){
          inputFile = new File(fileAPI.getRealAssetPath(assetInode, UtilMethods.getFileExtension(dotFile.getFileName())));
        }
        else if(respectFrontendRoles){
          if(realPath != null){
            inputFile = new File(realPath + LiveCache.getPathFromCache(id.getURI(), id.getHostId()));
          }else{
            inputFile = new File(FileUtil.getRealPath(assetPath + LiveCache.getPathFromCache(id.getURI(), id.getHostId())));
          }
        }else{
          if(realPath != null){
            inputFile = new File(realPath + WorkingCache.getPathFromCache(id.getURI(), id.getHostId()));
          }else{
            inputFile = new File(FileUtil.getRealPath(assetPath + WorkingCache.getPathFromCache(id.getURI(), id.getHostId())));
          }
        }
      }
      //DOTCMS-5674
      if(UtilMethods.isSet(fieldVarName)){
        params.put("fieldVarName", new String[]{fieldVarName});
        params.put("assetInodeOrIdentifier", new String[]{uuid});
      }
      data = exporter.exportContent(inputFile, params);

      // THIS IS WHERE THE MAGIC HAPPENS
      // save to session if user looking to edit a file
      if (req.getParameter(WebKeys.IMAGE_TOOL_SAVE_FILES) != null) {
                Map<String, String> files;
                if ( session != null && session.getAttribute( WebKeys.IMAGE_TOOL_SAVE_FILES ) != null ) {
                    files = (Map<String, String>) session.getAttribute( WebKeys.IMAGE_TOOL_SAVE_FILES );
                } else {
                    files = new HashMap<>();
                }
                String ext = UtilMethods.getFileExtension(data.getDataFile().getName());
          File tmp = File.createTempFile("binaryexporter", "." +ext);
          FileUtil.copyFile(data.getDataFile(), tmp);
          tmp.deleteOnExit();
          if (req.getParameter("binaryFieldId") != null) {
            files.put(req.getParameter("binaryFieldId"), tmp.getCanonicalPath());
          } else {
            files.put(fieldVarName, tmp.getCanonicalPath());
          }
          resp.getWriter().println(UtilMethods.encodeURIComponent(PublicEncryptionFactory.encryptString(tmp.getAbsolutePath())));
          resp.getWriter().close();
          resp.flushBuffer();
          return;
      }

      /*******************************
       *
       *  Start serving the data
       *
       *******************************/
      String mimeType = fileAPI.getMimeType(data.getDataFile().getName());

      if (mimeType == null)
        mimeType = "application/octet-stream";
      resp.setContentType(mimeType);

      if (req.getParameter("force_download") != null) {

        // if we are downloading a jpeg version of a png or gif
        String x = UtilMethods.getFileExtension(downloadName);
        String y = UtilMethods.getFileExtension(data.getDataFile().getName());
        if(!x.equals(y)){
          downloadName = downloadName.replaceAll("\\." + x, "\\." + y);
        }
        resp.setHeader("Content-Disposition", "attachment; filename=" + downloadName);
        resp.setHeader("Content-Type", "application/force-download");
      }

        int _daysCache = 365;
        GregorianCalendar expiration = new GregorianCalendar();
      expiration.add(java.util.Calendar.DAY_OF_MONTH, _daysCache);
      int seconds = (_daysCache * 24 * 60 * 60);

      long _lastModified = data.getDataFile().lastModified();
      if(_lastModified < 0) {
          _lastModified = 0;
      }
      // we need to round the _lastmodified to get rid of the milliseconds.
      _lastModified = _lastModified / 1000;
      _lastModified = _lastModified * 1000;
      Date _lastModifiedDate = new java.util.Date(_lastModified);

      long _fileLength = data.getDataFile().length();
      String _eTag = "dot:" + assetInode + ":" + _lastModified + ":" + _fileLength;

      SimpleDateFormat httpDate = new SimpleDateFormat(Constants.RFC2822_FORMAT);
      httpDate.setTimeZone(TimeZone.getTimeZone("GMT"));
            /* Setting cache friendly headers */
            resp.setHeader("Expires", httpDate.format(expiration.getTime()));
            resp.setHeader("Cache-Control", "public, max-age="+seconds);

            String ifModifiedSince = req.getHeader("If-Modified-Since");
            String ifNoneMatch = req.getHeader("If-None-Match");

            /*
             * If the etag matches then the file is the same
             *
            */
            if(ifNoneMatch != null){
                if(_eTag.equals(ifNoneMatch) || ifNoneMatch.equals("*")){
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED );
                    return;
                }
            }

            /* Using the If-Modified-Since Header */
             if(ifModifiedSince != null){
          try{
              Date ifModifiedSinceDate = httpDate.parse(ifModifiedSince);
              if(_lastModifiedDate.getTime() <= ifModifiedSinceDate.getTime()){
                  resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED );
                  return;
              }
          }
          catch(Exception e){}
      }

            resp.setHeader("Last-Modified", httpDate.format(_lastModifiedDate));
            resp.setHeader("Content-Length", String.valueOf(_fileLength));
            resp.setHeader("ETag", _eTag);
            //resp.setHeader("Content-Disposition", "attachment; filename=" + data.getDataFile().getName());
            FileInputStream is = new FileInputStream(data.getDataFile());
            int count = 0;
            byte[] buffer = new byte[4096];
            OutputStream servletOutput = resp.getOutputStream();
            while((count = is.read(buffer)) > 0) {
              servletOutput.write(buffer, 0, count);
            }
            servletOutput.close();
    } catch (DotContentletStateException e) {
      Logger.debug(BinaryExporterServlet.class, e.getMessage(),e);
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    } catch (DotRuntimeException e) {
      //Logger.error(BinaryExporterServlet.class, e.getMessage());
      Logger.debug(BinaryExporterServlet.class, e.getMessage(),e);
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    } catch (PortalException e) {
      Logger.error(BinaryExporterServlet.class, e.getMessage());
      Logger.debug(BinaryExporterServlet.class, e.getMessage(),e);
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    } catch (SystemException e) {
      Logger.error(BinaryExporterServlet.class, e.getMessage());
      Logger.debug(BinaryExporterServlet.class, e.getMessage(),e);
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    } catch (DotDataException e) {
      Logger.error(BinaryExporterServlet.class, e.getMessage());
      Logger.debug(BinaryExporterServlet.class, e.getMessage(),e);
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    } catch (DotSecurityException e) {
      try {
        if(WebAPILocator.getUserWebAPI().isLoggedToFrontend(req)){
          resp.sendError(HttpServletResponse.SC_FORBIDDEN);
        }else{
          resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
        }
      } catch (Exception e1) {
        Logger.error(BinaryExporterServlet.class,e1.getMessage(),e1);
        resp.sendError(HttpServletResponse.SC_FORBIDDEN);
      }
    } catch (BinaryContentExporterException e) {
      Logger.debug(BinaryExporterServlet.class, e.getMessage(),e);
      Logger.error(BinaryExporterServlet.class, e.getMessage());
      resp.sendError(HttpServletResponse.SC_NOT_FOUND);
    }
  }

  @SuppressWarnings("unchecked")
  private Map sortByKey(Map map) {
    List list = new LinkedList(map.entrySet());
    Collections.sort(list, new Comparator() {
      public int compare(Object o1, Object o2) {
        return ((Comparable) ((Map.Entry) (o1)).getKey()).compareTo(((Map.Entry) (o2)).getKey());
      }
    });
    // logger.info(list);
    Map result = new LinkedHashMap();
    for (Iterator it = list.iterator(); it.hasNext();) {
      Map.Entry entry = (Map.Entry) it.next();
      result.put(entry.getKey(), entry.getValue());
    }
    return result;
  }



  // Tries to find out whether this is content or a file
private boolean isContent(String id, boolean byInode, long langId, boolean respectFrontendRoles) throws DotStateException, DotDataException, DotSecurityException{



    if(cacheMisses.containsKey(id+byInode)){
      throw new DotStateException("404 - Unable to find id:" + id);
    }


    if(byInode){
      try {
        Contentlet c =APILocator.getContentletAPI().find(id, userAPI.getSystemUser(), true);
        if(c != null && c.getInode() != null)
          return true;
      } catch (Exception e) {
        Logger.debug(this.getClass(), "Unable to find contentlet " + id);
      }
      try {
        if(fileAPI.find(id,userAPI.getSystemUser(),false) != null){
          return false;
        }
      } catch (DotHibernateException e) {
        Logger.debug(this.getClass(), "cant find file with inode " + id);
      }
    }

    else{
      try {

        Identifier identifier = APILocator.getIdentifierAPI().loadFromCache(id);
        if(identifier != null){
          return "contentlet".equals(identifier.getAssetType());
        }

        //second check content check from lucene
        String luceneQuery = "+identifier:" + id;
        Contentlet c = APILocator.getContentletAPI().findContentletByIdentifier(id, false,langId, userAPI.getSystemUser(), false);
        if(c != null && UtilMethods.isSet(c.getInode())){
          return true;
        }

      } catch (Exception e) {
        Logger.debug(this.getClass(), "cant find identifier " + id);
      }
    }
    cacheMisses.put(id+byInode, true);
    throw new DotStateException("404 - Unable to find id:" + id);

  }
  @SuppressWarnings("deprecation")
  private Map cacheMisses = new LRUMap(1000);

  private Map<String,String[]> getURIParams(HttpServletRequest request){
    String url = request.getRequestURI().toString();
    url = (url.startsWith("/")) ? url.substring(1, url.length()) : url;
    String p[] = url.split("/");
    Map<String, String[]> map = new HashMap<String, String[]>();

    String key =null;
    for(String x : p){
      if(key ==null){
        key = x;
      }
      else{
        map.put(key, new String[]{x});
        key = null;
      }
    }

    return map;

  }



}
TOP

Related Classes of com.dotmarketing.servlets.BinaryExporterServlet

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.