Package jnlp.sample.servlet

Source Code of jnlp.sample.servlet.ResourceCatalog$PathEntries

/*
* @(#)ResourceCatalog.java  1.6 05/11/17
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
*  list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
*  this list of conditions and the following disclaimer in the documentation
*  and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/

package jnlp.sample.servlet;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.io.File;
import java.io.BufferedInputStream;
import javax.servlet.ServletContext;
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.w3c.dom.*;
import jnlp.sample.util.VersionString;
import jnlp.sample.util.VersionID;

public class ResourceCatalog {
    public static final String VERSION_XML_FILENAME = "version.xml";
   
    private Logger _log = null;
    private ServletContext _servletContext = null;
   
    private HashMap _entries;
   
    /** Class to contain the information we know
     *  about a specific directory
     */
    static private class PathEntries {
  /* Version-based entries at this particular path */
  private List _versionXmlList;
  private List _directoryList;
  private List _platformList;
  /* Last time this entry was updated */
  private long _lastModified; // Last modified time of entry;
 
  public PathEntries(List versionXmlList, List directoryList, List platformList, long lastModified) {
      _versionXmlList = versionXmlList;
      _directoryList = directoryList;
      _platformList = platformList;
      _lastModified = lastModified;
  }
 
 
  public void setDirectoryList(List dirList) {
      _directoryList = dirList;
  }

  public List getVersionXmlList() { return _versionXmlList; }
  public List getDirectoryList()  { return _directoryList; }
  public List getPlatformList()   { return _platformList; }
 
  public long getLastModified() { return _lastModified; }
    }
   
    public ResourceCatalog(ServletContext servletContext, Logger log) {
  _entries = new HashMap();
  _servletContext = servletContext;
  _log = log;
    }
   
   
    public JnlpResource lookupResource(DownloadRequest dreq) throws ErrorResponseException {
  // Split request up into path and name
  String path = dreq.getPath();
  String name = null;
  String dir  = null;
  int idx = path.lastIndexOf('/');
  if (idx == -1) {
      name = path;
  } else {
      name = path.substring(idx + 1); // Exclude '/'
      dir  = path.substring(0, idx + 1); // Include '/'
  }
 
  // Lookup up already parsed entries, and san directory for entries if neccesary
  PathEntries pentries =  (PathEntries)_entries.get(dir);
  JnlpResource xmlVersionResPath = new JnlpResource(_servletContext, dir + VERSION_XML_FILENAME);
  if (pentries == null || (xmlVersionResPath.exists() && xmlVersionResPath.getLastModified() > pentries.getLastModified())) {
      _log.addInformational("servlet.log.scandir", dir);
      List dirList = scanDirectory(dir, dreq);
      // Scan XML file
      List versionList = new ArrayList();
      List platformList = new ArrayList();
      parseVersionXML(versionList, platformList, dir, xmlVersionResPath);
      pentries = new PathEntries(versionList, dirList, platformList, xmlVersionResPath.getLastModified());
      _entries.put(dir, pentries);
  }
 
  // Search for a match
  JnlpResource[] result = new JnlpResource[1];
 
  if (dreq.isPlatformRequest()) {
      int sts = findMatch(pentries.getPlatformList(), name, dreq, result);
      if (sts != DownloadResponse.STS_00_OK) {
    throw new ErrorResponseException(DownloadResponse.getJnlpErrorResponse(sts));
      }
  } else {
      // First lookup in versions.xml file
      int sts1 = findMatch(pentries.getVersionXmlList(), name, dreq, result);
      if (sts1 != DownloadResponse.STS_00_OK) {
    // Then lookup in directory
    int sts2 = findMatch(pentries.getDirectoryList(), name, dreq, result)
    if (sts2 != DownloadResponse.STS_00_OK) {

        // fix for 4450104
        // try rescan and see if it helps
        pentries.setDirectoryList(scanDirectory(dir, dreq));
        sts2 = findMatch(pentries.getDirectoryList(), name, dreq, result);      
        // try again after rescanning directory
        if (sts2 != DownloadResponse.STS_00_OK) {
      // Throw the most specific error code
      throw new ErrorResponseException(DownloadResponse.getJnlpErrorResponse(Math.max(sts1, sts2)));
        }
    }
      }
  }
  return result[0];
    }
   
    /** This method finds the best match, or return the best error code. The
     *  result parameter must be an array with room for one element.
     *
     *  If a match is found, the method returns DownloadResponse.STS_00_OK
     *  If one or more entries matches on: name, version-id, os, arch, and locale,
     *  then the one with the highest version-id is set in the result[0] field.
     *
     *  If a match is not found, it returns an error code, either: ERR_10_NO_RESOURCE,
     *  ERR_11_NO_VERSION, ERR_20_UNSUP_OS, ERR_21_UNSUP_ARCH, ERR_22_UNSUP_LOCALE,
     *  ERR_23_UNSUP_JRE.
     *
     */
    public int findMatch(List list, String name, DownloadRequest dreq, JnlpResource[] result) {
  if (list == null) return DownloadResponse.ERR_10_NO_RESOURCE;
  // Setup return values
  VersionID bestVersionId = null;
  int error = DownloadResponse.ERR_10_NO_RESOURCE;
  VersionString vs = new VersionString(dreq.getVersion());
  // Iterate through entries
  for(int i = 0; i < list.size(); i++) {
      JnlpResource respath = (JnlpResource)list.get(i);
      VersionID vid = new VersionID(respath.getVersionId())
      int sts = matchEntry(name, vs, dreq, respath, vid);
      if (sts == DownloadResponse.STS_00_OK) {
    if (result[0] == null || vid.isGreaterThan(bestVersionId)) {
        result[0] = respath;
        bestVersionId = vid;
    }
      } else {
    error = Math.max(error, sts);
      }
  }
  return (result[0] != null) ? DownloadResponse.STS_00_OK : error;
    }
   
    public int matchEntry(String name, VersionString vs, DownloadRequest dreq, JnlpResource jnlpres, VersionID vid) {
  if (!name.equals(jnlpres.getName())) {
      return DownloadResponse.ERR_10_NO_RESOURCE;
  }
  if (!vs.contains(vid)) {
      return DownloadResponse.ERR_11_NO_VERSION;
  }
  if (!prefixMatchLists(jnlpres.getOSList(), dreq.getOS())) {
      return DownloadResponse.ERR_20_UNSUP_OS;
  }
  if (!prefixMatchLists(jnlpres.getArchList(), dreq.getArch())) {
      return DownloadResponse.ERR_21_UNSUP_ARCH;
  }
  if (!prefixMatchLists(jnlpres.getLocaleList(), dreq.getLocale())) {
      return DownloadResponse.ERR_22_UNSUP_LOCALE;
  }
  return DownloadResponse.STS_00_OK;
    }

      
    private static boolean prefixMatchStringList(String[] prefixList, String target) {
        // No prefixes matches everything
        if (prefixList == null) return true;
  // No target, but a prefix list does not match anything
  if (target == null) return false;
        for(int i = 0; i < prefixList.length; i++) {
            if (target.startsWith(prefixList[i])) return true;
        }
        return false;
    }
   
    /* Return true if at least one of the strings in 'prefixes' are a prefix
     * to at least one of the 'keys'.
     */
    public boolean prefixMatchLists(String[] prefixes, String[] keys) {
  // The prefixes are part of the server resources. If none is given,
  // everything matches
  if (prefixes == null) return true;
  // If no os keyes was given, and the server resource is keyed of this,
  // then return false.
  if (keys  == null) return false;
  // Check for a match on a key
  for(int i = 0; i < keys.length; i++) {
      if (prefixMatchStringList(prefixes, keys[i])) return true;
  }
  return false;
    }
   
    /** This method scans the directory pointed to by the
     *  given path and creates a list of ResourcePath elements
     *  that contains information about all the entries
     *
     *  The version-based information is encoded in the file name
     *  given the following format:
     *
     *     entry ::= <name> __ ( <options> ). <ext>
     *     options ::= <option> ( __ <options>  )?
     *     option  ::= V<version-id>
     *               | O<os>
     *               | A<arch>
     *               | L<locale>
     *
     */


    private String jnlpGetPath(DownloadRequest dreq) {
  // fix for 4474021
  // try to manuually generate the filename    
  // extract file name
  String path = dreq.getPath();      
  String filename = path.substring(path.lastIndexOf("/") + 1);
  path = path.substring(0, path.lastIndexOf("/") + 1);
  String name = filename;
  String ext = null;
 
  if (filename.lastIndexOf(".") != -1) {
      ext = filename.substring(filename.lastIndexOf(".") + 1);
     
      filename = filename.substring(0, filename.lastIndexOf("."));
     
  }
  if (dreq.getVersion() != null) {
      filename += "__V" + dreq.getVersion();
  }
 
  String[] temp = dreq.getOS();
 
  if (temp != null) {
      for (int i=0; i<temp.length; i++) {
    filename += "__O" + temp[i];
      }
  }
 
  temp = dreq.getArch();
 
  if (temp != null) {
      for (int i=0; i<temp.length; i++) {
    filename += "__A" + temp[i];
      }
  }
  temp = dreq.getLocale();
 
  if (temp != null) {
      for (int i=0; i<temp.length; i++) {
    filename += "__L" + temp[i];
      }
  }
 
  if (ext != null) {
      filename += "." + ext;
  }
 
  path += filename;
 
  return path;
    }

    public List scanDirectory(String dirPath, DownloadRequest dreq) {
  ArrayList list = new ArrayList();

  // fix for 4474021
  if (_servletContext.getRealPath(dirPath) == null) {
      String path = jnlpGetPath(dreq);  
   
      String name = dreq.getPath().substring(path.lastIndexOf("/") + 1);
 
      JnlpResource jnlpres = new JnlpResource(_servletContext, name, dreq.getVersion(), dreq.getOS(), dreq.getArch(), dreq.getLocale(), path, dreq.getVersion());    

      // the file does not exist
      if (jnlpres.getResource() == null) return null;   

      list.add(jnlpres);
      return list;
  }
  File dir = new File(_servletContext.getRealPath(dirPath));
  _log.addDebug("File directory: " + dir);
  if (dir.exists() && dir.isDirectory()) {
      File[] entries = dir.listFiles();
      for(int i = 0; i < entries.length; i++) {
    JnlpResource jnlpres = parseFileEntry(dirPath, entries[i].getName());
    if (jnlpres != null) {
        if (_log.isDebugLevel()) {
      _log.addDebug("Read file resource: " + jnlpres);
        }
        list.add(jnlpres);
    }
      }
  }
  return list;
    }
   
    private JnlpResource parseFileEntry(String dir, String filename) {
  int idx = filename .indexOf("__");
  if (idx == -1) return null;
 
  // Cut out name
  String name = filename.substring(0, idx);
  String rest = filename.substring(idx);
 
  // Cut out extension
  idx = rest.lastIndexOf('.');
  String extension = "";
  if (idx != -1 ) {
      extension = rest.substring(idx);
      rest = rest .substring(0, idx);
  }
 
  // Parse options
  String versionId = null;
  ArrayList osList = new ArrayList();
  ArrayList archList = new ArrayList();
  ArrayList localeList = new ArrayList();
  while(rest.length() > 0) {
      /* Must start with __ at this point */
      if (!rest.startsWith("__")) return null;
      rest = rest.substring(2);
      // Get option and argument
      char option = rest.charAt(0);
      idx = rest.indexOf("__");
      String arg = null;
      if (idx == -1) {
    arg = rest.substring(1);
    rest = "";
      } else {
    arg = rest.substring(1, idx);
    rest = rest.substring(idx);
      }
      switch(option) {
    case 'V': versionId = arg; break;
    case 'O': osList.add(arg); break;
    case 'A': archList.add(arg); break;
    case 'L': localeList.add(arg); break;
    default: return null; // error
      }
  }
 
  return new JnlpResource(_servletContext,
        name + extension, /* Resource name in URL request */
        versionId,
        listToStrings(osList),
        listToStrings(archList),
        listToStrings(localeList),
        dir + filename, /* Resource name in WAR file */
        versionId);
    }
   
    private String[] listToStrings(List list) {
  if (list.size() == 0) return null;
  return (String[])list.toArray(new String[list.size()]);
    }
   
    // Returns false if parsing failed
    private void parseVersionXML(final List versionList, final List platformList,
         final String dir, final JnlpResource versionRes) {
  if (!versionRes.exists()) return;
       
  // Parse XML into a more understandable format
  XMLNode root = null;
  try {
      DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
      DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
      Document doc = docBuilder.parse(new BufferedInputStream(versionRes.getResource().openStream()));
      doc.getDocumentElement().normalize();
     
      // Convert document into an XMLNode structure, since we already got utility methods
      //  to handle these. We should really use the data-binding stuff here - but that will come
      //  later
      //
      root = XMLParsing.convert(doc.getDocumentElement());
  } catch (SAXParseException err) {
      _log.addWarning("servlet.log.warning.xml.parsing",
          versionRes.getPath(),
          Integer.toString(err.getLineNumber()),
          err.getMessage());
      return;
  } catch (Throwable t) {
      _log.addWarning("servlet.log.warning.xml.reading", versionRes.getPath(), t);
      return;
  }
 
  // Check that root element is a <jnlp> tag
  if (!root.getName().equals("jnlp-versions")) {
      _log.addWarning("servlet.log.warning.xml.missing-jnlp", versionRes.getPath());
      return;
  }
 
  // Visit all <resource> elements
  XMLParsing.visitElements(root, "<resource>", new XMLParsing.ElementVisitor() {
        public void visitElement(XMLNode node) {
      XMLNode pattern = XMLParsing.findElementPath(node, "<pattern>");
      if (pattern == null) {
          _log.addWarning("servlet.log.warning.xml.missing-pattern", versionRes.getPath());
      } else {
          // Parse pattern
          String name =      XMLParsing.getElementContent(pattern , "<name>", "");
          String versionId = XMLParsing.getElementContent(pattern , "<version-id>");
          String[] os      = XMLParsing.getMultiElementContent(pattern, "<os>");
          String[] arch    = XMLParsing.getMultiElementContent(pattern, "<arch>");
          String[] locale = XMLParsing.getMultiElementContent(pattern, "<locale>");
          // Get return request
          String file = XMLParsing.getElementContent(node, "<file>");
          if (versionId == null || file == null) {
        _log.addWarning("servlet.log.warning.xml.missing-elems", versionRes.getPath());
          } else {
        JnlpResource res = new JnlpResource(_servletContext,
                    name,
                    versionId,
                    os,
                    arch,
                    locale,
                    dir + file,
                    versionId);
        if (res.exists()) {
            versionList.add(res);
            if (_log.isDebugLevel()) {
          _log.addDebug("Read resource: " + res);
            }
        } else {
            _log.addWarning("servlet.log.warning.missing-file", file, versionRes.getPath());
        }
          }
      }
        }
    });
 
  // Visit all <resource> elements
  XMLParsing.visitElements(root, "<platform>", new XMLParsing.ElementVisitor() {
        public void visitElement(XMLNode node) {
      XMLNode pattern = XMLParsing.findElementPath(node, "<pattern>");
      if (pattern == null) {
          _log.addWarning("servlet.log.warning.xml.missing-pattern", versionRes.getPath());
      } else {
          // Parse pattern
          String name =      XMLParsing.getElementContent(pattern , "<name>", "");
          String versionId = XMLParsing.getElementContent(pattern , "<version-id>");
          String[] os      = XMLParsing.getMultiElementContent(pattern, "<os>");
          String[] arch    = XMLParsing.getMultiElementContent(pattern, "<arch>");
          String[] locale = XMLParsing.getMultiElementContent(pattern, "<locale>");
          // Get return request
          String file = XMLParsing.getElementContent(node, "<file>");
          String productId = XMLParsing.getElementContent(node, "<product-version-id>");
         
          if (versionId == null || file == null || productId == null) {
        _log.addWarning("servlet.log.warning.xml.missing-elems2", versionRes.getPath());
          } else {
        JnlpResource res = new JnlpResource(_servletContext,
                    name,
                    versionId,
                    os,
                    arch,
                    locale,
                    dir + file,
                    productId);
        if (res.exists()) {
            platformList.add(res);
            if (_log.isDebugLevel()) {
          _log.addDebug("Read platform resource: " + res);
            }
        } else {
            _log.addWarning("servlet.log.warning.missing-file", file, versionRes.getPath());
        }
          }
      }
        }
    });
    }
}

TOP

Related Classes of jnlp.sample.servlet.ResourceCatalog$PathEntries

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.