       1 /*
       2  * $Id$
       3  *
       4  * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
       5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       6  *
       7  * This code is free software; you can redistribute it and/or modify it
       8  * under the terms of the GNU General Public License version 2 only, as
       9  * published by the Free Software Foundation.  Oracle designates this
      10  * particular file as subject to the "Classpath" exception as provided
      11  * by Oracle in the LICENSE file that accompanied this code.
      12  *
      13  * This code is distributed in the hope that it will be useful, but WITHOUT
      14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      16  * version 2 for more details (a copy is included in the LICENSE file that
      17  * accompanied this code).
      18  *
      19  * You should have received a copy of the GNU General Public License version
      20  * 2 along with this work; if not, write to the Free Software Foundation,
      21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      22  *
      23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      24  * or visit www.oracle.com if you need additional information or have any
      25  * questions.
      26  */
      27 package com.sun.javatest.agent;
      28
      29 import java.io.Reader;
      30 import java.io.BufferedReader;
      31 import java.io.InputStreamReader;
      32 import java.io.IOException;
      33 import java.lang.reflect.Constructor;
      34 import java.lang.reflect.InvocationTargetException;
      35 import java.net.URL;
      36 import java.nio.charset.StandardCharsets;
      37 import java.util.Enumeration;
      38 import java.util.Vector;
      39 import com.sun.javatest.util.StringArray;
      40 import java.io.PrintStream;
      41
      42 /**
      43  * A map provides a simple translation table for between configuration values
      44  * as provided by JT Harness and as required by an Agent. Typically, this is for
      45  * adjusting filenames because of differences introduced by different mount points
      46  * for various file systems.
      47  * <p>
      48  * This facility has been largely superceded by the map substitution mechanism
      49  * provided by environment files.
      50  */
      51 public class Map {
      52     /**
      53      * Read a map from a specified file.  This code is deliberately
      54      * written to tolerate Java platforms without a file system ...
      55      * as in some versions of Personal Java. Any problems caused by
      56      * the file system not being present are returned as IOExceptions
      57      * with a suitable detail message.
      58      * @param name The name of the file to read
      59      * @return The map read from the given file
      60      * @throws IOException if any errors occurred reading the file
      61      */
      62     public static Map readFile(String name) throws IOException {
      63         try {
      64             Class<?> c = Class.forName("java.io.FileReader"); // optional API in Jersonal Java
      65             Constructor m = c.getConstructor(new Class[] {String.class});
      66             Reader r = (Reader)(m.newInstance(new Object[] {name}));
      67             return new Map(r);
      68         }
      69         catch (ClassNotFoundException e) {
      70             throw new IOException("file system not accessible (" + e + ")");
      71         }
      72         catch (InvocationTargetException e) {
      73             Throwable t = e.getTargetException();
      74             if (t instanceof IOException)
      75                 throw (IOException)t;
      76             else
      77                 throw fileSystemProblem(t);
      78         }
      79         catch (IllegalAccessException e) {
      80             throw fileSystemProblem(e);
      81         }
      82         catch (InstantiationException e) {
      83             throw fileSystemProblem(e);
      84         }
      85         catch (NoSuchMethodException e) {
      86             throw fileSystemProblem(e);
      87         }
      88         catch (Error e) {
      89             throw fileSystemProblem(e);
      90         }
      91     }
      92
      93     /**
      94      * Read a map from a URL.
      95      * @param u The URL to read
      96      * @return The map read from the given URL
      97      * @throws IOException if any errors occurred reading the URL
      98      */
      99     public static Map readURL(URL u) throws IOException {
     100         return new Map(new InputStreamReader(u.openStream(), StandardCharsets.UTF_8.name()));
     101     }
     102
     103
     104     /**
     105      * Read a map from a local file (if the name does not begin with http:)
     106      * or from a URL if it does.  The method is simply a wrapper that delegates
     107      * to either {@link #readFile} or {@link #readURL} depending on the
     108      * argument.
     109      * @param name The name of the file or URL to read
     110      * @return The map read from the given location
     111      * @throws IOException if any errors occurred reading the map
     112      */
     113     public static Map readFileOrURL(String name) throws IOException {
     114         if (name.length() > 5 && name.substring(0, 5).equalsIgnoreCase("http:"))
     115             return readURL(new URL(name));
     116         else
     117             return readFile(name);
     118     }
     119
     120     private static IOException fileSystemProblem(Throwable t) {
     121         return new IOException("problem accessing file system: " + t);
     122     }
     123
     124     /**
     125      * Create a map by reading it from a given stream.
     126      * The '\u0020' sequence could be used to specify space symbol in the values.
     127      * @param r         The reader from which to read the map data. The reader is closed
     128      *                  after it has been completely read
     129      * @throws IOException if problems occur while reading the map data.
     130      */
     131     public Map(Reader r) throws IOException {
     132         BufferedReader in =
     133             (r instanceof BufferedReader ? (BufferedReader)r : new BufferedReader(r))
     134 ;
     135         // data arrives in rows, but we want it in columns
     136         Vector<String> from = new Vector<>();
     137         Vector<String> to = new Vector<>();
     138         String line;
     139         while ((line = in.readLine()) != null) {
     140             line = line.trim();
     141             if (line.length() > 0  &&  !line.startsWith("#")) {
     142                 String[] row = StringArray.split(line);
     143                 if (row.length < 2)
     144                     throw new IOException("format error in map file, line is: " + line);
     145                 from.addElement(row[0].replaceAll("\\Q\\u0020\\E", " "));
     146                 to.addElement(row[1].replaceAll("\\Q\\u0020\\E", " "));
     147             }
     148         }
     149         in.close();
     150
     151         fromValues = new String[from.size()];
     152         from.copyInto(fromValues);
     153         toValues = new String[to.size()];
     154         to.copyInto(toValues);
     155     }
     156
     157     /**
     158      * Translate the strings according to values in the map.
     159      * The strings are updated in place.
     160      * @param args      An array of strings to be translated according to the data
     161      *                  the map.
     162      */
     163     public void map(String[] args) {
     164         if (fromValues == null)
     165             return; // empty table
     166
     167         for (int i = 0; i < args.length; i++) {
     168             String arg = args[i];
     169             for (int j = 0; j < fromValues.length; j++) {
     170                 String f = fromValues[j];
     171                 String t = toValues[j];
     172                 for (int index = arg.indexOf(f);
     173                      index != -1;
     174                      index = arg.indexOf(f, index + t.length())) {
     175                     arg = arg.substring(0, index) + t + arg.substring(index + f.length());
     176                 }
     177             }
     178             if (tracing && arg != args[i]) {
     179                 traceOut.println("MAPARG-from: " + args[i]);
     180                 traceOut.println("MAPARG-to:   " + arg);
     181             }
     182             args[i] = arg;
     183         }
     184     }
     185
     186     /**
     187      * Creates a map from the specified <code>java.util.Map</code>.
     188      *
     189      * @param map the java.util.Map instance to take key-value pairs from
     190      */
     191     public Map(java.util.Map<String, String> map) {
     192         fromValues = new String[map.size()];
     193         toValues = new String[map.size()];
     194         int index = 0;
     195         for (java.util.Map.Entry<String, String> entry : map.entrySet()) {
     196             fromValues[index] = entry.getKey();
     197             toValues[index] = entry.getValue();
     198             index++;
     199         }
     200     }
     201
     202     /**
     203      * Enumerate the entries of the map.
     204      * @return an enumeration of the translation entries within the map
     205      */
     206     public Enumeration<String[]> enumerate() {
     207         Vector<String[]> v = new Vector<>(fromValues.length);
     208         for (int i = 0; i < fromValues.length; i++) {
     209             v.addElement(new String[] {fromValues[i], toValues[i]});
     210         }
     211         return v.elements();
     212     }
     213
     214     public void setTracing(boolean state, PrintStream out) {
     215         tracing = state;
     216         if (state) {
     217             traceOut = out;
     218         }
     219         else {
     220             traceOut = null;
     221         }
     222     }
     223
     224     private boolean tracing;
     225     private PrintStream traceOut;
     226     private String[] fromValues;
     227     private String[] toValues;
     228 }
    --- EOF ---