javamanager/javainstaller/installer/javasrc/com/nokia/mj/impl/installer/jadjarmatcher/JadJarMatcherBase.java
changeset 21 2a9601315dfc
child 23 98ccebc37403
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.mj.impl.installer.jadjarmatcher;
       
    20 
       
    21 import com.nokia.mj.impl.fileutils.FileUtility;
       
    22 import com.nokia.mj.impl.installer.integrityservice.IntegrityService;
       
    23 import com.nokia.mj.impl.installer.utils.FileUtils;
       
    24 import com.nokia.mj.impl.installer.utils.InstallerException;
       
    25 import com.nokia.mj.impl.installer.utils.JadReader;
       
    26 import com.nokia.mj.impl.installer.utils.Log;
       
    27 import com.nokia.mj.impl.utils.Attribute;
       
    28 import com.nokia.mj.impl.utils.InstallerDetailedErrorMessage;
       
    29 import com.nokia.mj.impl.utils.InstallerErrorMessage;
       
    30 import com.nokia.mj.impl.utils.JarManifestReader;
       
    31 import com.nokia.mj.impl.utils.OtaStatusCode;
       
    32 
       
    33 import java.io.IOException;
       
    34 import java.util.Hashtable;
       
    35 import java.util.Vector;
       
    36 
       
    37 /**
       
    38  * JadJarMatcher offers services for finding Jar when Jad filename is known,
       
    39  * and finding Jad when Jar filename is known.  JadJarMatcher only searches
       
    40  * files from local folders.
       
    41  *
       
    42  * @author Nokia Corporation
       
    43  * @version $Rev: 9457 $
       
    44  */
       
    45 public class JadJarMatcherBase
       
    46 {
       
    47     /** IntegrityService instance to be used when matching. */
       
    48     static IntegrityService iIntegrityService = null;
       
    49 
       
    50     /*** ----------------------------- PUBLIC ------------------------------ */
       
    51 
       
    52     /**
       
    53      * Set IntegrityService instance to be used when matching.
       
    54      */
       
    55     public static void setIntegrityService(IntegrityService aIs)
       
    56     {
       
    57         iIntegrityService = aIs;
       
    58     }
       
    59 
       
    60     /**
       
    61      * Searches for Jad file matching to given Jar file.
       
    62      *
       
    63      * @param aJar Jar file name.
       
    64      * @return JadJarFile containing matching file names.
       
    65      * @throws InstallerException if error occurs.
       
    66      */
       
    67     public static JadJarFile findJad(String aJar)
       
    68     {
       
    69         Log.log("JadJarMatcherBase: finding Jad for " + aJar);
       
    70         JadJarFile result = null;
       
    71         if (aJar != null)
       
    72         {
       
    73             result = getJarAttributes(aJar);
       
    74             if (result.iJadFilename != null)
       
    75             {
       
    76                 // Jad file was found from inside midlet message package,
       
    77                 // no need to find it.
       
    78                 Log.log("JadJarMatcherBase: Found jad from midlet message");
       
    79                 return result;
       
    80             }
       
    81             try
       
    82             {
       
    83                 findJad(result, listFiles(aJar, new String[] { ".jad" }));
       
    84             }
       
    85             catch (IOException ioe)
       
    86             {
       
    87                 InstallerException.internalError
       
    88                 ("Finding Jad failed for " + aJar, ioe);
       
    89             }
       
    90             if (result.iJadFilename == null)
       
    91             {
       
    92                 // Jad was not found from the same directory where Jar is.
       
    93                 Log.log("JadJarMatcherBase: Jad not found from the same folder");
       
    94             }
       
    95         }
       
    96         return result;
       
    97     }
       
    98 
       
    99     /**
       
   100      * Searches for Jar file matching to given Jad file.
       
   101      *
       
   102      * @param aJad Jad file name.
       
   103      * @param aJadCharset Character encoding used in Jad file.
       
   104      * @return JadJarFile containing matching file names.
       
   105      * @throws InstallerException if error occurs.
       
   106      */
       
   107     public static JadJarFile findJar(String aJad, String aJadCharset)
       
   108     {
       
   109         Log.log("JadJarMatcherBase: finding Jar for " + aJad);
       
   110         JadJarFile result = null;
       
   111         if (aJad != null)
       
   112         {
       
   113             result = getJadAttributes(aJad, aJadCharset);
       
   114             try
       
   115             {
       
   116                 findJar(result, listFiles(aJad, new String[] { ".jar", ".dcf", ".dm" }));
       
   117             }
       
   118             catch (IOException ioe)
       
   119             {
       
   120                 InstallerException.internalError
       
   121                 ("Finding Jar failed for " + aJad, ioe);
       
   122             }
       
   123             if (result.iJarFilename == null)
       
   124             {
       
   125                 // Jar was not found from the same directory where Jad is.
       
   126                 Log.log("JadJarMatcherBase: Jar not found from the same folder");
       
   127             }
       
   128         }
       
   129         return result;
       
   130     }
       
   131 
       
   132     /*** ---------------------------- PROTECTED --------------------------- */
       
   133 
       
   134     /**
       
   135      * Returns IntegrityService instance to be used when matching.
       
   136      */
       
   137     protected static IntegrityService getIntegrityService()
       
   138     {
       
   139         return iIntegrityService;
       
   140     }
       
   141 
       
   142     /**
       
   143      * Reads jad attributes from given file using given character encoding.
       
   144      *
       
   145      * @param aJad Jad file name.
       
   146      * @param aJadCharset Character encoding used in Jad file.
       
   147      * @return JadJarFile Jad file name and its attributes.
       
   148      * @throws InstallerException if error occurs.
       
   149      */
       
   150     protected static JadJarFile getJadAttributes(
       
   151         String aJad, String aJadCharset)
       
   152     {
       
   153         JadJarFile result = new JadJarFile();
       
   154         try
       
   155         {
       
   156             result.iJadFilename = aJad;
       
   157             result.iJadAttributes = JadReader.getAttributes(aJad, aJadCharset);
       
   158             if (result.iJadAttributes == null)
       
   159             {
       
   160                 throw new IOException("No Jad attributes found");
       
   161             }
       
   162         }
       
   163         catch (IOException ioe)
       
   164         {
       
   165             Log.logError("Exception while getting jad attributes: " + ioe);
       
   166             throw new InstallerException
       
   167             (InstallerErrorMessage.INST_CORRUPT_PKG, null,
       
   168              InstallerDetailedErrorMessage.INTERNAL_ERROR,
       
   169              new String[] { "Reading Jad failed: " + aJad },
       
   170              OtaStatusCode.INVALID_DESCRIPTOR, ioe);
       
   171         }
       
   172         return result;
       
   173     }
       
   174 
       
   175     /**
       
   176      * Reads jar attributes from given aJar file. Also checks if the
       
   177      * attributes indicate that this jar file is a midlet message package,
       
   178      * and if that's the case then extracts jad and jar files and
       
   179      * initializes the returned JadJarFile accordingly.
       
   180      *
       
   181      * @param aJar Jar file name.
       
   182      * @return JadJarFile Jar file name.
       
   183      * @throws InstallerException if error occurs.
       
   184      */
       
   185     protected static JadJarFile getJarAttributes(String aJar)
       
   186     {
       
   187         JadJarFile result = new JadJarFile();
       
   188         try
       
   189         {
       
   190             result.iJarFilename = aJar;
       
   191             result.iJarAttributes = JarManifestReader.getAttributes(aJar);
       
   192             if (result.iJarAttributes == null)
       
   193             {
       
   194                 throw new IOException("No Manifest attributes found");
       
   195             }
       
   196         }
       
   197         catch (IOException ioe)
       
   198         {
       
   199             Log.logError("Exception while getting jar attributes: " + ioe);
       
   200             throw new InstallerException
       
   201             (InstallerErrorMessage.INST_CORRUPT_PKG, null,
       
   202              InstallerDetailedErrorMessage.INTERNAL_ERROR,
       
   203              new String[] { "Reading Manifest failed: " + aJar },
       
   204              OtaStatusCode.INVALID_JAR, ioe);
       
   205         }
       
   206         // Check if jar file is a midlet message package.
       
   207         if (MidletMessageHandler.checkMidletMessage(result))
       
   208         {
       
   209             MidletMessageHandler.handleMidletMessage(aJar, result);
       
   210         }
       
   211         return result;
       
   212     }
       
   213 
       
   214     /**
       
   215      * Searches given aFiles for a match to Jar specified in aJadJarFile.
       
   216      * If a match is found, updates Jad details in aJadJarFile object.
       
   217      */
       
   218     protected static void findJad(JadJarFile aJadJarFile, FileList aFiles)
       
   219     throws IOException
       
   220     {
       
   221         MatchData jarMatch =
       
   222             MatchData.getMatchData(aJadJarFile.iJarAttributes);
       
   223         Log.log("JadJarMatcherBase: matching " + aJadJarFile.iJarFilename +
       
   224                 " (" + jarMatch + ")");
       
   225         if (aFiles.iFilenames.length > 1)
       
   226         {
       
   227             // Sort files so that the file which has the same
       
   228             // basename as the jar file will be matched first.
       
   229             aFiles.sortByBasename(aJadJarFile.iJarFilename);
       
   230         }
       
   231         Log.log("JadJarMatcherBase: Found " + aFiles.iFilenames.length +
       
   232                 " files:\n" + aFiles.toString());
       
   233         for (int i = 0; i < aFiles.iFilenames.length; i++)
       
   234         {
       
   235             aJadJarFile.iJadAttributes =
       
   236                 matchJad(jarMatch, aFiles.iFilenames[i]);
       
   237             if (aJadJarFile.iJadAttributes != null)
       
   238             {
       
   239                 aJadJarFile.iJadFilename = aFiles.iFilenames[i];
       
   240                 break;
       
   241             }
       
   242         }
       
   243     }
       
   244 
       
   245     /**
       
   246      * Searches given aFiles for a match to Jad specified in aJadJarFile.
       
   247      * If a match is found, updates Jar details in aJadJarFile object.
       
   248      */
       
   249     protected static void findJar(JadJarFile aJadJarFile, FileList aFiles)
       
   250     throws IOException
       
   251     {
       
   252         MatchData jadMatch =
       
   253             MatchData.getMatchData(aJadJarFile.iJadAttributes);
       
   254         Log.log("JadJarMatcherBase: matching " + aJadJarFile.iJadFilename +
       
   255                 " (" + jadMatch + ")");
       
   256         if (aFiles.iFilenames.length > 1)
       
   257         {
       
   258             // Sort files so that the file which has the same
       
   259             // basename as the jad file will be matched first.
       
   260             aFiles.sortByBasename(aJadJarFile.iJadFilename);
       
   261             // Sort files so that the file specified in
       
   262             // MIdlet-Jar-URL attribute will be matched first.
       
   263             String jarUrl = getMidletJarUrl(aJadJarFile);
       
   264             if (jarUrl != null)
       
   265             {
       
   266                 aFiles.sortByName(jarUrl, 0);
       
   267             }
       
   268         }
       
   269         Log.log("JadJarMatcherBase: Found " + aFiles.iFilenames.length +
       
   270                 " files:\n" + aFiles.toString());
       
   271         for (int i = 0; i < aFiles.iFilenames.length; i++)
       
   272         {
       
   273             aJadJarFile.iJarAttributes =
       
   274                 matchJar(jadMatch, aFiles.iFilenames[i]);
       
   275             if (aJadJarFile.iJarAttributes != null)
       
   276             {
       
   277                 aJadJarFile.iJarFilename = aFiles.iFilenames[i];
       
   278                 break;
       
   279             }
       
   280         }
       
   281     }
       
   282 
       
   283     /**
       
   284      * Returns a Hashtable of attributes read from Jar specified by
       
   285      * given aFilename if attributes in Jar match to given aJarMatch
       
   286      * data. If data does not match, this method returns null.
       
   287      */
       
   288     protected static Hashtable matchJad(MatchData aJarMatch, String aFilename)
       
   289     {
       
   290         Hashtable attrs = null;
       
   291         try
       
   292         {
       
   293             attrs = JadReader.getAttributes(aFilename);
       
   294         }
       
   295         catch (IOException ioe)
       
   296         {
       
   297             // Not a Jad file ==> no match.
       
   298             Log.log("JadJarMatcherBase: " + ioe.toString());
       
   299         }
       
   300         MatchData jadMatch = null;
       
   301         if (attrs != null)
       
   302         {
       
   303             jadMatch = MatchData.getMatchData(attrs);
       
   304             if (jadMatch.equals(aJarMatch))
       
   305             {
       
   306                 Log.log("JadJarMatcherBase: match " + aFilename);
       
   307                 return attrs;
       
   308             }
       
   309         }
       
   310         Log.log("JadJarMatcherBase: no match " + aFilename +
       
   311                 " (" + jadMatch + ")");
       
   312         return null;
       
   313     }
       
   314 
       
   315     /**
       
   316      * Returns a Hashtable of attributes read from Jad specified by
       
   317      * given aFilename if attributes in Jad match to given aJadMatch
       
   318      * data. If data does not match, this method returns null.
       
   319      */
       
   320     protected static Hashtable matchJar(MatchData aJadMatch, String aFilename)
       
   321     {
       
   322         Hashtable attrs = null;
       
   323         try
       
   324         {
       
   325             attrs = JarManifestReader.getAttributes(aFilename);
       
   326         }
       
   327         catch (IOException ioe)
       
   328         {
       
   329             // Not a Jar file ==> no match.
       
   330             Log.log("JadJarMatcherBase: " + ioe.toString());
       
   331         }
       
   332         MatchData jarMatch = null;
       
   333         if (attrs != null)
       
   334         {
       
   335             jarMatch = MatchData.getMatchData(attrs);
       
   336             if (jarMatch.equals(aJadMatch))
       
   337             {
       
   338                 Log.log("JadJarMatcherBase: match " + aFilename);
       
   339                 return attrs;
       
   340             }
       
   341         }
       
   342         Log.log("JadJarMatcherBase: no match " + aFilename +
       
   343                 " (" + jarMatch + ")");
       
   344         return null;
       
   345     }
       
   346 
       
   347     /**
       
   348      * Returns the value of MIDlet-Jar-URL attribute from given JadJarFile
       
   349      * object or null if the attribute does not exist.
       
   350      */
       
   351     protected static String getMidletJarUrl(JadJarFile aJadJarFile)
       
   352     {
       
   353         if (aJadJarFile == null || aJadJarFile.iJadAttributes == null)
       
   354         {
       
   355             return null;
       
   356         }
       
   357         return getAttributeValue(aJadJarFile.iJadAttributes, "MIDlet-Jar-URL");
       
   358     }
       
   359 
       
   360     /*** ----------------------------- PACKAGE ---------------------------- */
       
   361     /*** ----------------------------- PRIVATE ---------------------------- */
       
   362 
       
   363     /**
       
   364      * Returns an array of file names with specified extensions
       
   365      * from the same directory where given file exists.
       
   366      * Extension comparison is case insensitive.
       
   367      *
       
   368      * @param aFile files will be returned from the directory where
       
   369      * this file is located
       
   370      * @param aExts allowed extensions for returned files
       
   371      * @return FileList object containing arrays of file realted info
       
   372      * @returns IOException if an I/O error occurs
       
   373      */
       
   374     private static FileList listFiles(String aFile, String[] aExts) throws IOException
       
   375     {
       
   376         String name = FileUtils.getName(aFile);
       
   377         String path = aFile.substring(0, aFile.length()-name.length());
       
   378         if (path == null || path.length() == 0)
       
   379         {
       
   380             path = ".";
       
   381             //} else {
       
   382             // Else branch is not needed when FileUtility is used.
       
   383             // Add "." to make sure that CDC File understands that
       
   384             // path is directory.
       
   385             //path = path + ".";
       
   386         }
       
   387         for (int i = 0; i < aExts.length; i++)
       
   388         {
       
   389             aExts[i] = (aExts[i] == null? "": aExts[i].toLowerCase());
       
   390         }
       
   391         FileUtility[] files = new FileUtility(path).listFiles();
       
   392         Vector filenames = new Vector();
       
   393         Vector fileTimestamps = new Vector();
       
   394         for (int i = 0; i < files.length; i++)
       
   395         {
       
   396             // Leave out directories and files with incorrect extension
       
   397             // from the returned file list.
       
   398             String filename = FileUtility.getCanonicalPath(
       
   399                                   files[i].getAbsolutePath());
       
   400             if (files[i].isFile() &&
       
   401                     extMatches(filename.toLowerCase(), aExts))
       
   402             {
       
   403                 filenames.addElement(filename);
       
   404                 fileTimestamps.addElement(new Long(files[i].lastModified()));
       
   405             }
       
   406         }
       
   407         String[] resultFilenames = new String[filenames.size()];
       
   408         long[] resultTimestamps = new long[fileTimestamps.size()];
       
   409         for (int i = 0; i < filenames.size(); i++)
       
   410         {
       
   411             resultFilenames[i] = (String)filenames.elementAt(i);
       
   412             resultTimestamps[i] = ((Long)fileTimestamps.elementAt(i)).longValue();
       
   413         }
       
   414         // Construct a FileList object to be returned and sort it by time
       
   415         // distance from the file where listing was started from.
       
   416         FileList fileList = new FileList(resultFilenames, null, resultTimestamps);
       
   417         fileList.initTimeDistances((new FileUtility(aFile)).lastModified());
       
   418         fileList.sortByTimeDistance();
       
   419         return fileList;
       
   420     }
       
   421 
       
   422     /**
       
   423      * Returns true if given file has one of the specified extensions,
       
   424      * false otherwise. Comparison is case sensitive.
       
   425      */
       
   426     private static boolean extMatches(String aFile, String[] aExts)
       
   427     {
       
   428         boolean result = false;
       
   429         for (int i = 0; i < aExts.length; i++)
       
   430         {
       
   431             if (aFile.endsWith(aExts[i]))
       
   432             {
       
   433                 result = true;
       
   434                 break;
       
   435             }
       
   436         }
       
   437         return result;
       
   438     }
       
   439 
       
   440     /**
       
   441      * Returns requested attribute value from given Hashtable,
       
   442      * or null if attribute does not exist.
       
   443      */
       
   444     private static String getAttributeValue(
       
   445         Hashtable aAttributes, String aName)
       
   446     {
       
   447         Attribute attr = (Attribute)aAttributes.get(aName);
       
   448         if (attr != null && attr.getValue() != null)
       
   449         {
       
   450             return attr.getValue().trim();
       
   451         }
       
   452         return null;
       
   453     }
       
   454 
       
   455     protected static class MatchData
       
   456     {
       
   457         private String iName = null;
       
   458         private String iVendor = null;
       
   459         private String iVersion = null;
       
   460 
       
   461         private MatchData()
       
   462         {
       
   463         }
       
   464 
       
   465         private MatchData(String aName, String aVendor, String aVersion)
       
   466         {
       
   467             iName = aName;
       
   468             iVendor = aVendor;
       
   469             iVersion = aVersion;
       
   470         }
       
   471 
       
   472         public static MatchData getMatchData(Hashtable aAttributes)
       
   473         {
       
   474             return new MatchData(
       
   475                        getAttributeValue(aAttributes, "MIDlet-Name"),
       
   476                        getAttributeValue(aAttributes, "MIDlet-Vendor"),
       
   477                        getAttributeValue(aAttributes, "MIDlet-Version"));
       
   478         }
       
   479 
       
   480         public int hashCode()
       
   481         {
       
   482             int result = 0;
       
   483             if (iName != null)
       
   484             {
       
   485                 result += iName.hashCode();
       
   486             }
       
   487             if (iVendor != null)
       
   488             {
       
   489                 result += iVendor.hashCode();
       
   490             }
       
   491             if (iVersion != null)
       
   492             {
       
   493                 result += iVersion.hashCode();
       
   494             }
       
   495             return result;
       
   496         }
       
   497 
       
   498         public boolean equals(Object aObj)
       
   499         {
       
   500             if (!(aObj instanceof MatchData))
       
   501             {
       
   502                 return false;
       
   503             }
       
   504             MatchData md = (MatchData)aObj;
       
   505             if (equals(this.iName, md.iName) &&
       
   506                     equals(this.iVendor, md.iVendor) &&
       
   507                     equals(this.iVersion, md.iVersion))
       
   508             {
       
   509                 return true;
       
   510             }
       
   511             return false;
       
   512         }
       
   513 
       
   514         public String toString()
       
   515         {
       
   516             StringBuffer buf = new StringBuffer();
       
   517             buf.append("Name: " + iName);
       
   518             buf.append(", Vendor: " + iVendor);
       
   519             buf.append(", Version: " + iVersion);
       
   520             return buf.toString();
       
   521         }
       
   522 
       
   523         private static boolean equals(String aStr1, String aStr2)
       
   524         {
       
   525             if ((aStr1 == null && aStr2 == null) ||
       
   526                     (aStr1 != null && aStr1.equals(aStr2)))
       
   527             {
       
   528                 return true;
       
   529             }
       
   530             return false;
       
   531         }
       
   532     }
       
   533 
       
   534     /*** ----------------------------- NATIVE ----------------------------- */
       
   535 }