AppPathService.java

  1. /*
  2.  * Copyright (c) 2002-2022, City of Paris
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  *  1. Redistributions of source code must retain the above copyright notice
  10.  *     and the following disclaimer.
  11.  *
  12.  *  2. Redistributions in binary form must reproduce the above copyright notice
  13.  *     and the following disclaimer in the documentation and/or other materials
  14.  *     provided with the distribution.
  15.  *
  16.  *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
  17.  *     contributors may be used to endorse or promote products derived from
  18.  *     this software without specific prior written permission.
  19.  *
  20.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
  24.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30.  * POSSIBILITY OF SUCH DAMAGE.
  31.  *
  32.  * License 1.0
  33.  */
  34. package fr.paris.lutece.portal.service.util;

  35. import java.io.File;
  36. import java.io.FileInputStream;
  37. import java.io.IOException;
  38. import java.text.MessageFormat;
  39. import java.util.Enumeration;
  40. import java.util.StringTokenizer;

  41. import javax.servlet.ServletContext;
  42. import javax.servlet.http.HttpServletRequest;
  43. import javax.servlet.http.HttpSession;

  44. import org.apache.commons.lang3.StringUtils;

  45. import fr.paris.lutece.portal.service.datastore.DatastoreService;
  46. import fr.paris.lutece.portal.service.message.SiteMessageService;
  47. import fr.paris.lutece.portal.service.security.SecurityTokenService;
  48. import fr.paris.lutece.portal.web.LocalVariables;
  49. import fr.paris.lutece.portal.web.constants.Parameters;
  50. import fr.paris.lutece.util.ReferenceList;
  51. import fr.paris.lutece.util.stream.StreamUtil;
  52. import fr.paris.lutece.util.string.StringUtil;
  53. import fr.paris.lutece.util.url.UrlItem;

  54. /**
  55.  * this class provides services for locate repository or url
  56.  */
  57. public final class AppPathService
  58. {
  59.     public static final String SESSION_BASE_URL = "base_url";
  60.     private static final String MSG_LOG_PROPERTY_NOT_FOUND = "Property {0} not found in the properties file ";
  61.     private static final int PORT_NUMBER_HTTP = 80;
  62.     private static final String PROPERTY_BASE_URL = "lutece.base.url";
  63.     private static final String PROPERTY_PORTAL_URL = "lutece.portal.path";
  64.     private static final String PROPERTY_SITE_MESSAGE_URL = "lutece.siteMessage.path";
  65.     private static final String PROPERTY_ADMIN_URL = "lutece.admin.path";
  66.     private static final String PROPERTY_ADMIN_MENU_URL = "lutece.admin.menu.url";
  67.     private static final String PROPERTY_PORTAL_REDIRECT_URL = "lutece.portal.redirect.url";
  68.     private static final String PROPERTY_VIRTUAL_HOST_KEYS = "virtualHostKeys";
  69.     private static final String PROPERTY_VIRTUAL_HOST_KEY_PARAMETER = "virtualHostKey.parameterName";
  70.     private static final String PROPERTY_VIRTUAL_HOST = "virtualHost.";
  71.     private static final String PROPERTY_PREFIX_URL = "url.";
  72.     private static final String PROPERTY_PROD_BASE_URL = "lutece.prod.url";
  73.     private static final String PROPERTY_INSTANCE = "lutece.webapp.instance";
  74.     private static final String INSTANCE_DEFAULT = "default";
  75.     private static final String SUFFIX_BASE_URL = ".baseUrl";
  76.     private static final String SUFFIX_DESCRIPTION = ".description";
  77.     private static final String SLASH = "/";
  78.     private static final String DOUBLE_POINTS = ":";

  79.     // Datastore keys
  80.     private static final String KEY_ADMIN_HOME_URL = "portal.site.site_property.admin_home_url";
  81.     private static final String KEY_PORTAL_HOME_URL = "portal.site.site_property.home_url";
  82.     private static String _strWebAppPath;

  83.     /**
  84.      * Creates a new AppPathService object.
  85.      */
  86.     private AppPathService( )
  87.     {
  88.     }

  89.     /**
  90.      * Initialize The path service
  91.      *
  92.      * @param context
  93.      *            The servlet context
  94.      */
  95.     public static void init( ServletContext context )
  96.     {
  97.         String strRealPath = context.getRealPath( "/" );
  98.         _strWebAppPath = normalizeWebappPath( strRealPath );
  99.     }

  100.     /**
  101.      * Initialize The webapppath
  102.      *
  103.      * @param strWebAppPath
  104.      *            The Webapp path
  105.      */
  106.     public static void init( String strWebAppPath )
  107.     {
  108.         _strWebAppPath = normalizeWebappPath( strWebAppPath );
  109.     }

  110.     /**
  111.      * Returns the absolute path of a repository from a relative definition in properties file
  112.      *
  113.      *
  114.      * @return the repository absolute path
  115.      * @param strKey
  116.      *            the repository key definied in properties file
  117.      */
  118.     public static String getPath( String strKey )
  119.     {
  120.         // Adds relative path found from strKey
  121.         String strDirectory = AppPropertiesService.getProperty( strKey );

  122.         if ( strDirectory == null )
  123.         {
  124.             Object [ ] propertyMissing = {
  125.                     strKey
  126.             };
  127.             String strMsg = MessageFormat.format( MSG_LOG_PROPERTY_NOT_FOUND, propertyMissing );
  128.             throw new AppException( strMsg );
  129.         }

  130.         return getWebAppPath( ) + strDirectory;
  131.     }

  132.     /**
  133.      * Returns the webapp path from the properties file
  134.      *
  135.      *
  136.      * @return the webapp path
  137.      */
  138.     public static String getWebAppPath( )
  139.     {
  140.         return _strWebAppPath;
  141.     }

  142.     /**
  143.      * Returns the absolute path of file from its relative definition in properties file.
  144.      *
  145.      * @param strKey
  146.      *            the repository key defined in properties file
  147.      * @param strFilename
  148.      *            The name of file
  149.      * @return the absolute path of file
  150.      */
  151.     public static String getPath( String strKey, String strFilename )
  152.     {
  153.         return getPath( strKey ) + SLASH + strFilename;
  154.     }

  155.     /**
  156.      * Gets a file as stream
  157.      *
  158.      * @param strPath
  159.      *            the path
  160.      * @param strFilename
  161.      *            The name of file
  162.      * @return a FileInput Stream object
  163.      */
  164.     public static FileInputStream getResourceAsStream( String strPath, String strFilename )
  165.     {
  166.         String strFilePath = getWebAppPath( ) + strPath + strFilename;

  167.         FileInputStream fis = null;
  168.         try
  169.         {
  170.             File file = new File( strFilePath );
  171.             fis = new FileInputStream( file );

  172.             return fis;
  173.         }
  174.         catch( IOException e )
  175.         {
  176.             StreamUtil.safeClose( fis );
  177.             throw new AppException( "Unable to get file : " + strFilePath );
  178.         }
  179.     }

  180.     /**
  181.      * Returns the absolute path of a repository from a relative path
  182.      *
  183.      *
  184.      * @return the repository absolute path
  185.      * @param strDirectory
  186.      *            the relative path
  187.      */
  188.     public static String getAbsolutePathFromRelativePath( String strDirectory )
  189.     {
  190.         return _strWebAppPath + strDirectory;
  191.     }

  192.     /**
  193.      * Return the url of the webapp, built from the request
  194.      *
  195.      * @param request
  196.      *            The HttpServletRequest
  197.      * @return strBase the webapp url
  198.      */
  199.     public static String getBaseUrl( HttpServletRequest request )
  200.     {
  201.         if ( request == null )
  202.         {
  203.             return getBaseUrl( );
  204.         }

  205.         String strBase;

  206.         // Search for a Virtual Host Base Url defined in the request
  207.         strBase = getVirtualHostBaseUrl( request );

  208.         // If not found, get the base url from session
  209.         if ( ( strBase == null ) || strBase.equals( StringUtils.EMPTY ) )
  210.         {
  211.             HttpSession session = request.getSession( false );

  212.             if ( session != null )
  213.             {
  214.                 Object oBase = session.getAttribute( SESSION_BASE_URL );

  215.                 if ( oBase != null )
  216.                 {
  217.                     strBase = (String) oBase;
  218.                 }
  219.             }
  220.         }

  221.         // If not found, get the base url from the config.properties
  222.         if ( ( strBase == null ) || ( strBase.equals( StringUtils.EMPTY ) ) )
  223.         {
  224.             strBase = AppPropertiesService.getProperty( PROPERTY_BASE_URL );
  225.         }

  226.         if ( ( strBase == null ) || ( strBase.equals( StringUtils.EMPTY ) ) )
  227.         {
  228.             // Dynamic base URL if not defined in the properties
  229.             strBase = request.getScheme( ) + DOUBLE_POINTS + SLASH + SLASH + request.getServerName( );

  230.             int nPort = request.getServerPort( );

  231.             if ( nPort != PORT_NUMBER_HTTP )
  232.             {
  233.                 strBase += ( DOUBLE_POINTS + nPort );
  234.             }

  235.             strBase += request.getContextPath( );
  236.         }

  237.         if ( !strBase.endsWith( SLASH ) )
  238.         {
  239.             strBase += SLASH;
  240.         }

  241.         return strBase;
  242.     }

  243.     /**
  244.      * Return the url of the webapp. The method should only be used out of request context (by daemons for example). If there is a request context, use
  245.      * {@link AppPathService#getBaseUrl(HttpServletRequest)} instead.
  246.      *
  247.      * @return The webapp url, or null if the 'lutece.base.url' property has not been set.
  248.      * @deprecated Use {@link AppPathService#getBaseUrl(HttpServletRequest)} instead
  249.      */
  250.     @Deprecated
  251.     public static String getBaseUrl( )
  252.     {
  253.         HttpServletRequest request = LocalVariables.getRequest( );

  254.         if ( request != null )
  255.         {
  256.             return getBaseUrl( request );
  257.         }

  258.         // FIXME : lutece.base.url is only set when using WSSO
  259.         String strBaseUrl = AppPropertiesService.getProperty( PROPERTY_BASE_URL );

  260.         if ( strBaseUrl == null )
  261.         {
  262.             strBaseUrl = StringUtils.EMPTY;
  263.         }
  264.         else
  265.         {
  266.             if ( !strBaseUrl.endsWith( SLASH ) )
  267.             {
  268.                 strBaseUrl += SLASH;
  269.             }
  270.         }

  271.         return strBaseUrl;
  272.     }

  273.     /**
  274.      * Return the webapp prod url (or the base url if no prod url has been definied).
  275.      *
  276.      * @param request
  277.      *            The HTTP request
  278.      * @return The prod url
  279.      */
  280.     public static String getProdUrl( HttpServletRequest request )
  281.     {
  282.         String strBaseUrl = AppPropertiesService.getProperty( PROPERTY_PROD_BASE_URL );

  283.         if ( StringUtils.isBlank( strBaseUrl ) )
  284.         {
  285.             strBaseUrl = getBaseUrl( request );
  286.         }

  287.         if ( !strBaseUrl.endsWith( SLASH ) )
  288.         {
  289.             strBaseUrl += SLASH;
  290.         }

  291.         return strBaseUrl;
  292.     }

  293.     /**
  294.      * Return the webapp prod url. If no prod URL has been defined, then the base URL is returned
  295.      *
  296.      * @param strBaseUrl
  297.      *            The base URL
  298.      * @return The prod url
  299.      */
  300.     public static String getProdUrl( String strBaseUrl )
  301.     {
  302.         String strProdUrl = AppPropertiesService.getProperty( PROPERTY_PROD_BASE_URL );

  303.         if ( StringUtils.isBlank( strProdUrl ) )
  304.         {
  305.             strProdUrl = strBaseUrl;
  306.         }

  307.         if ( ( strProdUrl != null ) && !strProdUrl.endsWith( SLASH ) )
  308.         {
  309.             strProdUrl += SLASH;
  310.         }

  311.         return strProdUrl;
  312.     }

  313.     /**
  314.      * Return the url of the webapp, built from the request
  315.      *
  316.      * @param request
  317.      *            The HttpServletRequest
  318.      * @return strBase the webapp url
  319.      */
  320.     public static String getSiteMessageUrl( HttpServletRequest request )
  321.     {
  322.         // Set the site message url
  323.         return SiteMessageService.setSiteMessageUrl( getBaseUrl( request ) + getSiteMessageUrl( ) );
  324.     }

  325.     /**
  326.      * Returns the portal page relative url (jsp/site/Portal.jsp) defined in lutece.properties
  327.      *
  328.      * @return the Portal Url
  329.      */
  330.     public static String getPortalUrl( )
  331.     {
  332.         return AppPropertiesService.getProperty( PROPERTY_PORTAL_URL );
  333.     }

  334.     /**
  335.      * Returns the forward URL for webapp's root path. Default is (jsp/site/Portal.jsp) defined in lutece.properties
  336.      *
  337.      * @return the Portal Root forward Url
  338.      */
  339.     public static String getRootForwardUrl( )
  340.     {
  341.         return DatastoreService.getDataValue( KEY_PORTAL_HOME_URL, AppPropertiesService.getProperty( PROPERTY_PORTAL_REDIRECT_URL ) );
  342.     }

  343.     /**
  344.      * Returns the Site Message relative url (jsp/site/SiteMessage.jsp) defined in lutece.properties
  345.      *
  346.      * @return the SiteMessage Url
  347.      */
  348.     public static String getSiteMessageUrl( )
  349.     {
  350.         return AppPropertiesService.getProperty( PROPERTY_SITE_MESSAGE_URL );
  351.     }

  352.     /**
  353.      * Returns the admin portal page relative url (jsp/admin/site/AdminSite.jsp) defined in lutece.properties
  354.      *
  355.      * @return the Portal Url
  356.      */
  357.     public static String getAdminPortalUrl( )
  358.     {
  359.         return AppPropertiesService.getProperty( PROPERTY_ADMIN_URL );
  360.     }

  361.     /**
  362.      * Returns the admin menu page relative url (jsp/admin/site/AdminMenu.jsp) defined in lutece.properties
  363.      *
  364.      * @return the Admin Menu Url
  365.      */
  366.     public static String getAdminMenuUrl( )
  367.     {
  368.         return DatastoreService.getDataValue( KEY_ADMIN_HOME_URL, AppPropertiesService.getProperty( PROPERTY_ADMIN_MENU_URL ) );
  369.     }

  370.     /**
  371.      * Normalizes the Webapp Path
  372.      *
  373.      * @param strPath
  374.      *            The path to normalize
  375.      * @return The normalized path
  376.      */
  377.     private static String normalizeWebappPath( String strPath )
  378.     {
  379.         String strNormalized = strPath;

  380.         // For windows, remove the leading \
  381.         if ( ( strNormalized.length( ) > 3 ) && ( strNormalized.indexOf( ':' ) == 2 ) )
  382.         {
  383.             strNormalized = strNormalized.substring( 1 );
  384.         }

  385.         // convert Windows path separator if present
  386.         strNormalized = StringUtil.substitute( strNormalized, "/", "\\" );

  387.         // remove the ending separator if present
  388.         if ( strNormalized.endsWith( "/" ) )
  389.         {
  390.             strNormalized = strNormalized.substring( 0, strNormalized.length( ) - 1 );
  391.         }

  392.         return strNormalized;
  393.     }

  394.     // //////////////////////////////////////////////////////////////////////////
  395.     // Multiple virtual hosts configuration management
  396.     /**
  397.      * Gets available virtual hosts defined in the config.properties
  398.      *
  399.      * @return A reference list containing the key and the description of each virtual host configuration. The list is empty if there is no configuration
  400.      *         defined.
  401.      */
  402.     public static ReferenceList getAvailableVirtualHosts( )
  403.     {
  404.         ReferenceList list = null;

  405.         // Get keys list form config.properties
  406.         String strKeysList = AppPropertiesService.getProperty( PROPERTY_VIRTUAL_HOST_KEYS );

  407.         if ( strKeysList != null )
  408.         {
  409.             list = new ReferenceList( );

  410.             // Extracts each key (separated by a comma)
  411.             StringTokenizer strTokens = new StringTokenizer( strKeysList, "," );

  412.             while ( strTokens.hasMoreTokens( ) )
  413.             {
  414.                 String strHostKey = strTokens.nextToken( );
  415.                 String strHostKeyDescription = AppPropertiesService.getProperty( PROPERTY_VIRTUAL_HOST + strHostKey + SUFFIX_DESCRIPTION );
  416.                 list.addItem( strHostKey, strHostKeyDescription );
  417.             }
  418.         }

  419.         return list;
  420.     }

  421.     /**
  422.      * Gets a Virtual Host Key if the request contains a virtual host key
  423.      *
  424.      * @param request
  425.      *            The HTTP request
  426.      * @return A Virtual Host Key if present, otherwise null.
  427.      */
  428.     public static String getVirtualHostKey( HttpServletRequest request )
  429.     {
  430.         String strVirtalHostKey = null;

  431.         // Get from config.properties the parameter name for virtual host keys
  432.         String strVirtualHostKeyParameter = AppPropertiesService.getProperty( PROPERTY_VIRTUAL_HOST_KEY_PARAMETER );

  433.         if ( ( request != null ) && ( strVirtualHostKeyParameter != null ) && ( !strVirtualHostKeyParameter.equals( "" ) ) )
  434.         {
  435.             // Search for this parameter into the request
  436.             strVirtalHostKey = request.getParameter( strVirtualHostKeyParameter );
  437.         }

  438.         return strVirtalHostKey;
  439.     }

  440.     /**
  441.      * Gets a Base Url for a virtual host if the request contains a virtual host key
  442.      *
  443.      * @param request
  444.      *            The HTTP request
  445.      * @return A virtual host base url if present, otherwise null.
  446.      */
  447.     private static String getVirtualHostBaseUrl( HttpServletRequest request )
  448.     {
  449.         String strBaseUrl = null;
  450.         String strVirtalHostKey = getVirtualHostKey( request );

  451.         if ( ( strVirtalHostKey != null ) && ( !strVirtalHostKey.equals( "" ) ) )
  452.         {
  453.             // If found gets the Base url for this virtual host by its key
  454.             strBaseUrl = AppPropertiesService.getProperty( PROPERTY_VIRTUAL_HOST + strVirtalHostKey + SUFFIX_BASE_URL );
  455.         }

  456.         return strBaseUrl;
  457.     }

  458.     /**
  459.      * Build the url item to use for a url that includes the redirection parameter for reconnection.
  460.      *
  461.      * @param strRootUrl
  462.      *            the root part of the url, to build an absolute url
  463.      * @param strUrlPropertySuffixKey
  464.      *            The property suffix to retrieve the url
  465.      * @return an absolute url, completed with the redirectUrl parameter (contains the relative part of the url), as an UrlItem
  466.      */
  467.     public static UrlItem buildRedirectUrlItem( String strRootUrl, String strUrlPropertySuffixKey )
  468.     {
  469.         String strUrl = AppPropertiesService.getProperty( PROPERTY_PREFIX_URL + strUrlPropertySuffixKey );
  470.         UrlItem url = new UrlItem( strRootUrl + strUrl );
  471.         url.addParameter( Parameters.REDIRECT_URL, strUrlPropertySuffixKey );

  472.         return url;
  473.     }

  474.     /**
  475.      * Retrieve the url to redirect to after login. It is given by the redirectUrl parameter if found. The request parameters are copied (except the login and
  476.      * acces code and token). This is to be used by the doLogin method of AdminLoginJspBean.
  477.      *
  478.      * @param request
  479.      *            the http request
  480.      * @param strDefaultRedirectUrl
  481.      *            the default url to go to after login
  482.      * @return an UrlItem corresponding to the url to redirect to after login.
  483.      */
  484.     public static UrlItem resolveRedirectUrl( HttpServletRequest request, String strDefaultRedirectUrl )
  485.     {
  486.         String strUrl = strDefaultRedirectUrl;

  487.         String strUrlKey = request.getParameter( Parameters.REDIRECT_URL );
  488.         String strRedirectUrl = null;

  489.         if ( strUrlKey != null )
  490.         {
  491.             strRedirectUrl = AppPropertiesService.getProperty( PROPERTY_PREFIX_URL + strUrlKey );
  492.         }

  493.         if ( strRedirectUrl != null )
  494.         {
  495.             strUrl = strRedirectUrl;
  496.         }

  497.         Enumeration enumParams = request.getParameterNames( );
  498.         UrlItem url = new UrlItem( getBaseUrl( request ) + strUrl );

  499.         String strParamName;

  500.         while ( enumParams.hasMoreElements( ) )
  501.         {
  502.             strParamName = (String) enumParams.nextElement( );

  503.             if ( !strParamName.equals( Parameters.REDIRECT_URL ) && !strParamName.equals( Parameters.ACCESS_CODE )
  504.                     && !strParamName.equals( Parameters.PASSWORD ) && !strParamName.equals( SecurityTokenService.PARAMETER_TOKEN ) )
  505.             {
  506.                 url.addParameter( strParamName, request.getParameter( strParamName ) );
  507.             }
  508.         }

  509.         return url;
  510.     }

  511.     /**
  512.      * Returns the absolute url corresponding to the given one, if the later was found to be relative. An url starting with "http://" is absolute. A relative
  513.      * url should be given relatively to the webapp root.
  514.      *
  515.      * @param request
  516.      *            the http request (provides the base path if needed)
  517.      * @param strUrl
  518.      *            the url to transform
  519.      * @return the corresonding absolute url
  520.      *
  521.      *
  522.      */
  523.     public static String getAbsoluteUrl( HttpServletRequest request, String strUrl )
  524.     {
  525.         if ( ( strUrl != null ) && !strUrl.startsWith( "http://" ) && !strUrl.startsWith( "https://" ) )
  526.         {
  527.             return AppPathService.getBaseUrl( request ) + strUrl;
  528.         }

  529.         return strUrl;
  530.     }

  531.     /**
  532.      * Gets the webapp instance defined in the config.properties file with the key lutece.webapp.instance
  533.      *
  534.      * @return The instance name
  535.      * @since 4.1
  536.      */
  537.     public static String getWebappInstance( )
  538.     {
  539.         String strInstance = AppPropertiesService.getProperty( PROPERTY_INSTANCE );

  540.         if ( ( strInstance != null ) && ( !strInstance.equals( StringUtils.EMPTY ) ) )
  541.         {
  542.             return strInstance;
  543.         }

  544.         return INSTANCE_DEFAULT;
  545.     }

  546.     /**
  547.      * Returns whether the current instance is the default webapp instance
  548.      *
  549.      * @return true if default, otherwise false
  550.      */
  551.     public static boolean isDefaultWebappInstance( )
  552.     {
  553.         return INSTANCE_DEFAULT.equals( getWebappInstance( ) );
  554.     }
  555. }