001/*
002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved.
003 * 
004 * http://www.izforge.com/izpack/
005 * http://developer.berlios.de/projects/izpack/
006 * 
007 * Copyright 2005 Klaus Bartz
008 *
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 *     http://www.apache.org/licenses/LICENSE-2.0
014 *     
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 */
021
022package com.coi.tools.os.win;
023
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.MissingResourceException;
028import java.util.ResourceBundle;
029
030/**
031 * A exception class which will be used from the native part of system dependent classes to signal
032 * exceptions. The native methods writes only symbolic error messages, the language dependant
033 * mapping will be done in this class.
034 * 
035 * @author Klaus Bartz
036 * 
037 */
038public class NativeLibException extends Exception
039{
040
041    private static final long serialVersionUID = 3257002172494721080L;
042
043    /** Map of founded resource bundles which contains the localized error messages. */
044    private final static HashMap messageResourceBundles = new HashMap();
045
046    /** Internal error as number. */
047    private int libErr;
048
049    /** OS error as number. */
050    private int osErr;
051
052    /** Internal error message; contains most the symbolic error name. */
053    private String libErrString;
054
055    /** OS error string; if possible localized. */
056    private String osErrString;
057
058    /** Additional arguments. */
059    private ArrayList args = new ArrayList();
060
061    static
062    {
063        // add the first resource bundle
064        addResourceBundle("com.coi.tools.os.win.resources.NativeLibErr");
065    }
066
067    /**
068     * Adds a resource bundle which contains localized error messages. The bundlePath should contain
069     * a string with which the bundle is loadable with ResourceBundle.getBundle, may be the full
070     * class path to a ListResourceBundle. The localize is done by getBundle, therefore the path
071     * should not contain the locale substring. At a call to getMessage the bundle is searched with
072     * the libErrString as key. If it exist, the value of it is used by getMessage, else the
073     * libErrString self.
074     * 
075     * @param bundlePath path of bundle without locale
076     */
077    public static void addResourceBundle(String bundlePath)
078    {
079        ResourceBundle bd = null;
080        if (messageResourceBundles.containsKey(bundlePath)) return;
081        try
082        {
083            bd = ResourceBundle.getBundle(bundlePath);
084        }
085        catch (MissingResourceException mre)
086        {
087            mre.printStackTrace();
088        }
089        messageResourceBundles.put(bundlePath, bd);
090        return;
091
092    }
093
094    /**
095     * The constructor.
096     */
097    public NativeLibException()
098    {
099        super();
100    }
101
102    /**
103     * Creates a NativeLibException with the given message.
104     * 
105     * @param message to be used
106     */
107    public NativeLibException(String message)
108    {
109        super(message);
110    }
111
112    /**
113     * Creates a NativeLibException with the given cause.
114     * 
115     * @param cause to be used
116     */
117    public NativeLibException(Throwable cause)
118    {
119        super(cause);
120    }
121
122    /**
123     * Creates a NativeLibException with the given message and cause.
124     * 
125     * @param message message to be used
126     * @param cause cause to be used
127     */
128    public NativeLibException(String message, Throwable cause)
129    {
130        super(message, cause);
131    }
132
133    /**
134     * Creates a NativeLibException with the given values.
135     * 
136     * @param libErr identifier of the internal handled error
137     * @param osErr system error number
138     * @param libString message for the internal handled error
139     * @param osString system error message
140     */
141    public NativeLibException(int libErr, int osErr, String libString, String osString)
142    {
143        super();
144        this.libErr = libErr;
145        this.osErr = osErr;
146        libErrString = libString;
147        osErrString = osString;
148    }
149
150    /*
151     * (non-Javadoc)
152     * 
153     * @see java.lang.Throwable#getMessage()
154     */
155    public String getMessage()
156    {
157        StringBuffer retval = new StringBuffer();
158        boolean next = false;
159        if (libErrString != null)
160        {
161            retval.append(getLocalizedLibMessage());
162            next = true;
163        }
164        else if (libErr != 0)
165        {
166            if (next) retval.append("\n");
167            next = true;
168            retval.append(getMsg("libErrNumber." + Integer.toString(libErr)));
169        }
170        if (osErr != 0)
171        {
172            if (next) retval.append("\n");
173            next = true;
174            retval.append(getMsg("libInternal.OsErrNumPraefix")).append(Integer.toString(osErr));
175        }
176        if (osErrString != null)
177        {
178            if (next) retval.append("\n");
179            next = true;
180            // Message self should be localized in the native part
181            retval.append(getMsg("libInternal.OsErrStringPraefix")).append(getOsMessage());
182        }
183        if (retval.length() > 0) return (reviseMsgWithArgs(retval.toString()));
184        return null;
185    }
186
187    /**
188     * Returns the number of the internal handled error.
189     * 
190     * @return the number of the internal handled error
191     */
192    public int getLibErr()
193    {
194        return libErr;
195    }
196
197    /**
198     * Returns the message of the internal handled error.
199     * 
200     * @return the messager of the internal handled error
201     */
202    public String getLibMessage()
203    {
204        return libErrString;
205    }
206
207    /**
208     * Returns the localized message of the internal handled error.
209     * 
210     * @return the localized message of the internal handled error
211     */
212    public String getLocalizedLibMessage()
213    {
214        return (getMsg(libErrString));
215    }
216
217    /**
218     * Returns the number of the system error.
219     * 
220     * @return the number of the system error
221     */
222    public int getOsErr()
223    {
224        return (osErr);
225    }
226
227    /**
228     * Returns the message of the system error.
229     * 
230     * @return the messager of the system error
231     */
232    public String getOsMessage()
233    {
234        return (osErrString);
235    }
236
237    /**
238     * Adds a string to the internal argument list.
239     * 
240     * @param arg string to be added to the internal argument list
241     */
242    public void addArgument(String arg)
243    {
244        args.add(arg);
245    }
246
247    /**
248     * Returns the internal argument list.
249     * 
250     * @return the internal argument list
251     */
252    public ArrayList getArguments()
253    {
254        return (args);
255    }
256
257    public String reviseMsgWithArgs(String msg)
258    {
259        for (int i = 0; i < args.size(); ++i)
260        {
261            String key = "{" + Integer.toString(i) + "}";
262            msg = replaceString(msg, key, (String) args.get(i));
263        }
264        return (msg);
265    }
266
267    /**
268     * Searches the resource bundles for a string which coresponds to the given string as key.
269     * 
270     * @param s string which should be used as keys for the resource bundle
271     * @return the founded message as int value
272     */
273
274    private String getMsg(String s)
275    {
276        Iterator it = messageResourceBundles.values().iterator();
277        while (it.hasNext())
278        {
279            try
280            {
281                return (((ResourceBundle) it.next()).getString(s));
282            }
283            catch (MissingResourceException missingresourceexception)
284            { // do not throw, else look in next bundle.
285                ;
286            }
287        }
288        return (s);
289    }
290
291    /**
292     * Returns a string resulting from replacing all occurrences of what in this string with with.
293     * In opposite to the String.replaceAll method this method do not use regular expression or
294     * other methods which are only available in JRE 1.4 and later.
295     * 
296     * @param destination string for which the replacing should be performed
297     * @param what what string should be replaced
298     * @param with with what string what should be replaced
299     * @return a new String object if what was found in the given string, else the given string self
300     */
301    private static String replaceString(String destination, String what, String with)
302    {
303        if (destination.indexOf(what) >= 0)
304        { // what found, with (placeholder) not included in destination ->
305            // perform changing.
306            StringBuffer buf = new StringBuffer();
307            int last = 0;
308            int current = destination.indexOf(what);
309            int whatLength = what.length();
310            while (current >= 0)
311            { // Do not use Methods from JRE 1.4 and higher ...
312                if (current > 0) buf.append(destination.substring(last, current));
313                buf.append(with);
314                last = current + whatLength;
315                current = destination.indexOf(what, last);
316            }
317            if (destination.length() > last) buf.append(destination.substring(last));
318            return buf.toString();
319        }
320        return destination;
321    }
322
323}