Package org.apache.wookie.server

Source Code of org.apache.wookie.server.LocalizedResourceFilter

/*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.wookie.server;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.configuration.Configuration;
import org.apache.wookie.beans.IWidget;
import org.apache.wookie.beans.IWidgetInstance;
import org.apache.wookie.beans.util.IPersistenceManager;
import org.apache.wookie.beans.util.PersistenceManagerFactory;
import org.apache.wookie.w3c.util.LocalizationUtils;
import org.apache.wookie.w3c.util.WidgetPackageUtils;

import com.ibm.icu.util.ULocale;

/**
* A Filter for implementing rules for folder-based localization. Redirects
* requests for widget resources to resources in appropriate locale folders.
*
* Note that this relies on servlet session management, which relies on cookies
* being enabled in the browser.
*
* This filter runs for a lot of what are otherwise completely static resources,
* so its a real drag on server performance
*/
public class LocalizedResourceFilter implements Filter {

  private FilterConfig filterConfig = null;

  public void destroy() {
  }

  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException {

    // We use the "localized" querystring parameter to indicate a resource
    // has already been processed by this algorithm once, to prevent hunting and
    // infinite recursion
    String localized = ((HttpServletRequest) request).getParameter("localized");
   
    //
    // Skip if already localized
    //
    if (localized == null) {

      //
      // Get the Widget this resource request is related to
      //
      IWidget widget = getWidgetFromRequest(request);

      //
      // Only if we have a valid instance and a resource which has no
      // localization parameter do we start the locale algorithm
      //
      if (widget != null) {
       
        //
        // Get the original request URL
        //
        String uri = ((HttpServletRequest) request).getRequestURL().toString();
        URL url = new URL(uri);
        String path = url.getPath();

        //
        // Process the resource with the localization algorithm
        //
        String localizedPath = getLocalizedResource(path);

        //
        // Redirect to localized resource URL only if different from the
        // original resource URL
        //
        if (!path.equals(localizedPath)) {
          uri = uri.replace(path, localizedPath);
          if (uri.contains("?")) {
            uri += "&localized=1";
          } else {
            uri += "?localized=1";
          }
          URL newUrl = new URL(uri);
          ((HttpServletResponse) response).sendRedirect(newUrl.toString());
          return;
        }
      }
    }
    chain.doFilter(request, response);
  }

  public void init(FilterConfig filterConfig) throws ServletException {
    this.filterConfig = filterConfig;
  }

  /**
   * Process a resource path in the context of a widget instance, identify the
   * path for any resource which matches the path in a locale folder which
   * matches the locale preference for the widget instance.
   *
   * If no locale preference is set for the instance, the default server locale
   * is used.
   *
   * If no localized path can be determined, the method returns the original
   * path supplied.
   *
   * @param originalPath
   * @param instance
   * @return the localized path for the resource; if none is found, the original
   *         path is returned
   */
  private String getLocalizedResource(String originalPath) {
   
    //
    // Remove the context URI from the path, or this will mess up
    // the algorithm for locating the file using its real path
    //
    String context = filterConfig.getServletContext().getContextPath();
    String basePath = originalPath.substring(originalPath.indexOf(context)
        + context.length());

    //
    // Strip out the widget base path to obtain just the resource itself
    //
    String widgetPath = getWidgetBasePath();
    int start = originalPath.indexOf(widgetPath) + widgetPath.length();
    String resource;
    try {
      resource = originalPath.substring(start);
    } catch (Exception e) {
      return originalPath;
    }

    //
    // If the resource already contains a locale, remove it for the purposes of
    // searching
    // This is because local links within widgets can target localized files -
    // e.g.
    // In the example widget below, there will be a link from
    // locales/es/index.html to "locales/es/images/test.png"
    // but we need to consider this as a request for /images/test.png
    //
    // index.html
    // /images/test.png
    // /locales/es/index.html
    //
    if (resource.startsWith("locales/")) {
      String[] parts = resource.split("/");
      String prefix = "/" + parts[0] + "/" + parts[1] + "/";
      String nonLocalResource = resource.substring(resource.indexOf(prefix)
          + prefix.length());
      basePath = basePath.replace(resource, nonLocalResource);
      resource = nonLocalResource;
    }

    //
    // For each locale in the list see if a matching localized resource exists.
    // If it does, return it and terminate this algorithm
    //
    List<ULocale> locales = LocalizationUtils.getProcessedLocaleList(new String[] { getPreferredLocale() });
    for (ULocale locale : locales) {
      String path = basePath.replace(resource, "locales/" + locale.toLanguageTag().toLowerCase() + "/" + resource);
      String filePath = filterConfig.getServletContext().getRealPath(path);
      if (new File(filePath).exists())
        return context + path;
    }

    //
    // As the next resort, we'll try defautLocale
    //
    String defaultLocale = getWidgetDefaultLocale();
    if (defaultLocale != null) {
      String path = basePath.replace(resource, "locales/" + defaultLocale.toLowerCase() + "/" + resource);
      String filePath = filterConfig.getServletContext().getRealPath(path);
      if (new File(filePath).exists())
        return context + path;
    }

    //
    // All attempts to locate a localized copy have failed, so we must try to
    // find a non-localized version instead
    //
    if (new File(filterConfig.getServletContext().getRealPath(basePath)).exists())
      return context + basePath;

    //
    // No localized or even non-localized file exists, so just return the
    // original. This situation shouldn't arise except
    // where, e.g., the original request was for a non-existing resource
    //
    return originalPath;
  }

  /**
   * Return the base path for a widget instance
   *
   * @param instance
   * @return
   */
  private String getWidgetBasePath() {
    Configuration config = (Configuration) filterConfig.getServletContext().getAttribute("properties");
    final String localWidgetFolderPath = filterConfig.getServletContext().getContextPath() + config.getString("widget.widgetfolder");
    return WidgetPackageUtils.getURLForWidget(localWidgetFolderPath, getWidgetGuid(), "");
  }
 
  /**
   * Inspect the request path and identify the widget based on the path
   * components
   *
   * @param request
   * @return
   */
  private IWidget getWidgetFromRequest(ServletRequest request) {
    //
    // If I have an instance key in the query, use it to look up the widget
    // it belongs to, and put the widget URI and localization preferences into the session
    //
    // This will only happen if the resource is the Start File for the Widget
    //
    String idkey = ((HttpServletRequest) request).getParameter("idkey");
    if (idkey != null){
      IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager();
      IWidgetInstance instance = persistenceManager.findWidgetInstanceByIdKey(idkey);
      if (instance != null) {
        filterConfig.getServletContext().setAttribute("widget-id", instance.getWidget().getGuid());
        filterConfig.getServletContext().setAttribute("widget-instance-locale", instance.getLang());
        filterConfig.getServletContext().setAttribute("widget-default-locale", instance.getWidget().getDefaultLocale());
        return instance.getWidget();
      }
    }

    //
    // Get the widget id from the session, and if its not null, obtain the widget it relates to
    //
    String guid = (String) filterConfig.getServletContext().getAttribute("widget-id");
    if (guid != null) {
      IPersistenceManager persistenceManager = PersistenceManagerFactory.getPersistenceManager();
      return persistenceManager.findWidgetByGuid(guid);
    }
   
    //
    // No widget found
    //
    return null;
  }
 
  /**
   * Get the GUID of the widget that the resource in the current context belongs to
   * @return
   */
  private String getWidgetGuid(){
    return (String) filterConfig.getServletContext().getAttribute("widget-id");
  }
 
  /**
   * Get the preferred locale of the widget instances that the resource in the current context belongs to
   * @return
   */
  private String getPreferredLocale(){
    return (String) filterConfig.getServletContext().getAttribute("widget-instance-locale");
  }
 
  /**
   * Get the defaultLocale attribute for the widget that the resource in the current context belongs to
   * @return
   */
  private String getWidgetDefaultLocale(){
    return (String) filterConfig.getServletContext().getAttribute("widget-default-locale");
  }

}
TOP

Related Classes of org.apache.wookie.server.LocalizedResourceFilter

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.