All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.mgwt.linker.server.Html5ManifestServletBase Maven / Gradle / Ivy

package com.googlecode.mgwt.linker.server;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import com.googlecode.mgwt.linker.linker.ManifestWriter;
import com.googlecode.mgwt.linker.linker.PermutationMapLinker;
import com.googlecode.mgwt.linker.linker.XMLPermutationProvider;
import com.googlecode.mgwt.linker.linker.XMLPermutationProviderException;
import com.googlecode.mgwt.linker.server.propertyprovider.MgwtOsPropertyProvider;
import com.googlecode.mgwt.linker.server.propertyprovider.PropertyProvider;
import com.googlecode.mgwt.linker.server.propertyprovider.PropertyProviderException;

public class Html5ManifestServletBase extends HttpServlet {

  private static final long serialVersionUID = -2540671294104865306L;
  private XMLPermutationProvider permutationProvider;

  private Map propertyProviders = new HashMap();

  public Html5ManifestServletBase() {
    permutationProvider = new XMLPermutationProvider();
  }

  protected void addPropertyProvider(PropertyProvider propertyProvider) {
    propertyProviders.put(propertyProvider.getPropertyName(), propertyProvider);
  }

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    String moduleName = getModuleName(req);

    String baseUrl = getBaseUrl(req);

    Set computedBindings = calculateBindinPropertiesForClient(req);

    String strongName = getPermutationStrongName(baseUrl, moduleName, computedBindings);

    if (strongName != null) {
      String manifest = readManifest(baseUrl + moduleName + "/" + strongName + PermutationMapLinker.PERMUTATION_MANIFEST_FILE_ENDING);
      serveStringManifest(req, resp, manifest);
      return;
    }

    boolean isIPhoneWithoutCookie = isIphoneWithoutCookie(computedBindings);
    boolean isIPadWithoutCookie = isIpadWithoutCookie(computedBindings);

    if (isIPhoneWithoutCookie || isIPadWithoutCookie) {
      Set nonRetinaMatch = new HashSet();
      Set retinaMatch = new HashSet();

      if (isIPhoneWithoutCookie) {
        computedBindings.remove(MgwtOsPropertyProvider.iPhone_undefined);
        nonRetinaMatch.add(MgwtOsPropertyProvider.iPhone);
        retinaMatch.add(MgwtOsPropertyProvider.retina);
      }

      if (isIPadWithoutCookie) {
        computedBindings.remove(MgwtOsPropertyProvider.iPad_undefined);
        nonRetinaMatch.add(MgwtOsPropertyProvider.iPad);
        retinaMatch.add(MgwtOsPropertyProvider.iPad_retina);
      }

      nonRetinaMatch.addAll(computedBindings);
      retinaMatch.addAll(computedBindings);

      String moduleNameNonRetina = getPermutationStrongName(baseUrl, moduleName, nonRetinaMatch);
      String moduleNameRetina = getPermutationStrongName(baseUrl, moduleName, retinaMatch);

      if (moduleNameNonRetina != null && moduleNameRetina != null) {

        // load files for both permutations
        Set filesForPermutation = getFilesForPermutation(baseUrl, moduleName, moduleNameNonRetina);
        filesForPermutation.addAll(getFilesForPermutation(baseUrl, moduleName, moduleNameRetina));

        // dynamically write a new manifest..
        ManifestWriter manifestWriter = new ManifestWriter();
        String writeManifest = manifestWriter.writeManifest(new HashSet(), filesForPermutation);
        serveStringManifest(req, resp, writeManifest);
        return;
      }
    }

    // if we got here we just don`t know the device react with 500 -> no
    // manifest...
    throw new ServletException("unkown device");
  }

  protected String getBaseUrl(HttpServletRequest req) {
    String base = req.getServletPath();
    // cut off module
    return base.substring(0, base.lastIndexOf("/") + 1);
  }

  public boolean isIphoneWithoutCookie(Set bps) {
    for (BindingProperty bp : bps) {
      if ("mgwt.os".equals(bp.getName())) {
        if ("iphone_undefined".equals(bp.getValue())) {
          // oh shit this is an iphone
          // so now we need to serve two manifests
          // retina...
          // non retina

          return true;

        }
      }
    }
    return false;
  }

  public boolean isIpadWithoutCookie(Set bps) {
    for (BindingProperty bp : bps) {
      if ("mgwt.os".equals(bp.getName())) {
        if ("ipad_undefined".equals(bp.getValue())) {
          // oh shit this is an ipad
          // so now we need to serve two manifests
          // retina...
          // non retina
          return true;
        }
      }
    }
    return false;
  }

  public Set getFilesForPermutation(String baseUrl, String moduleName, String permutation) throws ServletException {
    String fileName = baseUrl + moduleName + "/" + permutation + PermutationMapLinker.PERMUTATION_FILE_ENDING;
    XMLPermutationProvider xmlPermutationProvider = new XMLPermutationProvider();

    InputStream inputStream = null;
    try {
      File file = new File(getServletContext().getRealPath(fileName));
      inputStream = new FileInputStream(file);
      return xmlPermutationProvider.getPermutationFiles(inputStream);
    } catch (XMLPermutationProviderException e) {
      log("can not read permutation file");
      throw new ServletException("can not read permutation file", e);
    } catch (FileNotFoundException e) {
      log("can not read permutation file");
      throw new ServletException("can not read permutation file", e);
    } finally {
      closeQuitly(inputStream);
    }
  }

  public String readManifest(String filePath) throws ServletException {
    File manifestFile = new File(getServletContext().getRealPath(filePath));

    StringWriter manifestWriter = new StringWriter();
    BufferedReader br = null;
    try {
      br = new BufferedReader(new InputStreamReader(new FileInputStream(manifestFile), "UTF-8"));

      String line = null;

      while ((line = br.readLine()) != null) {
        manifestWriter.append(line + "\n");
      }

      return manifestWriter.toString();
    } catch (FileNotFoundException e) {
      log("could not find manifest file", e);
      throw new ServletException("can not find manifest file", e);
    } catch (IOException e) {
      log("error while reading manifest file", e);
      throw new ServletException("error while reading manifest file", e);
    } finally {
      closeQuitly(br);
    }
  }

  /**
   * @param req
   * @return
   * @throws PropertyProviderException
   */
  public Set calculateBindinPropertiesForClient(HttpServletRequest req) throws ServletException {

    try {
      Set computedBindings = new HashSet();

      Set> set = propertyProviders.entrySet();
      for (Entry entry : set) {
        String varValue = entry.getValue().getPropertyValue(req);
        BindingProperty bindingProperty = new BindingProperty(entry.getKey(), varValue);
        computedBindings.add(bindingProperty);
      }
      return computedBindings;
    } catch (PropertyProviderException e) {
      log("cam not calculate properties for client", e);
      throw new ServletException("can not calculate properties for client", e);
    }
  }

  public void serveStringManifest(HttpServletRequest req, HttpServletResponse resp, String manifest) throws ServletException {
    resp.setHeader("Cache-Control", "no-cache");
    resp.setHeader("Pragma", "no-cache");
    resp.setDateHeader("Expires", new Date().getTime());

    resp.setContentType("text/cache-manifest");

    try {
      InputStream is = new ByteArrayInputStream(manifest.getBytes("UTF-8"));
      ServletOutputStream os = resp.getOutputStream();
      byte[] buffer = new byte[1024];
      int bytesRead;

      while ((bytesRead = is.read(buffer)) != -1) {
        os.write(buffer, 0, bytesRead);
      }
      return;
    } catch (UnsupportedEncodingException e) {
      log("can not write manifest to output stream", e);
      throw new ServletException("can not write manifest to output stream", e);
    } catch (IOException e) {
      log("can not write manifest to output stream", e);
      throw new ServletException("can not write manifest to output stream", e);
    }
  }

  public String getPermutationStrongName(String baseUrl, String moduleName, Set computedBindings) throws ServletException {

    if (moduleName == null) {
      throw new IllegalArgumentException("moduleName can not be null");
    }

    if (computedBindings == null) {
      throw new IllegalArgumentException("computedBindings can not be null");
    }

    String realPath = getServletContext().getRealPath(baseUrl + moduleName + "/" + PermutationMapLinker.MANIFEST_MAP_FILE_NAME);

    FileInputStream fileInputStream = null;
    try {

      fileInputStream = new FileInputStream(realPath);

      Map> map = permutationProvider.getBindingProperties(fileInputStream);
      for (Entry> entry : map.entrySet()) {
        List value = entry.getValue();
        if (value.containsAll(computedBindings) && value.size() == computedBindings.size()) {
          return entry.getKey();
        }
      }
      return null;
    } catch (FileNotFoundException e) {
      log("can not find file: '" + realPath + "'", e);
      throw new ServletException("can not find permutation file", e);
    } catch (XMLPermutationProviderException e) {
      log("can not read xml file", e);
      throw new ServletException("can not read permutation information", e);
    } finally {
      closeQuitly(fileInputStream);
    }
  }

  public String getModuleName(HttpServletRequest req) throws ServletException {
    if (req == null) {
      throw new IllegalArgumentException("reqeust can not be null");
    }

    // request url should be something like .../modulename.manifest" within
    // the same folder of your host page...
    Pattern pattern = Pattern.compile("/([a-zA-Z0-9_]+)\\.manifest$");
    Matcher matcher = pattern.matcher(req.getServletPath());
    if (!matcher.find()) {
      log("can not calculate module base from url: '" + req.getServletPath() + "'");
      throw new ServletException("can not calculate module base from url: '" + req.getServletPath() + "'");
    }

    String module = matcher.group(1);
    return module;
  }

  private void closeQuitly(BufferedReader br) {
    if (br != null) {
      try {
        br.close();
      } catch (IOException ignored) {
      }
    }
  }

  private void closeQuitly(InputStream stream) {
    if (stream != null) {
      try {
        stream.close();
      } catch (IOException ignored) {
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy