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 2002 Marcus Stursberg
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.izforge.izpack.installer;
023
024import java.io.ByteArrayOutputStream;
025import java.io.IOException;
026import java.io.InputStream;
027import java.net.URL;
028
029import javax.swing.ImageIcon;
030
031/**
032 * With this ResourceManager you are able to get resources from the jar file.
033 * 
034 * All resources are loaded language dependent as it's done in java.util.ResourceBundle. To set a
035 * language dependent resource just append '_' and the locale to the end of the Resourcename<br>
036 * <br>
037 * Example:
038 * <li> InfoPanel.info - for default value</li>
039 * <li> InfoPanel.info_deu - for german value</li>
040 * <li> InfoPanel.info_eng - for english value</li>
041 * <br>
042 * 
043 * This class is almost a singleton. It is created once using <code>create</code> by the installer
044 * and later, the instance is retrieved using <code>getInstance</code>.
045 * 
046 * @author Marcus Stursberg
047 */
048public class ResourceManager
049{
050
051    /**
052     * Contains the current language of the installer The locale is taken from
053     * InstallData#installData#getAttribute("langpack") If there is no language set, the language is
054     * english.
055     */
056    private String locale = "";
057
058    /** The base path where to find the resources */
059    protected final String resourceBasePath = "/res/";
060
061    /** Contains the given InstallData */
062    private AutomatedInstallData installData;
063
064    /** The instance of this class. */
065    private static ResourceManager instance = null;
066
067    /**
068     * Constructor. Protected because this is a singleton.
069     * 
070     * @param data - the current installData
071     */
072    protected ResourceManager(AutomatedInstallData data)
073    {
074        this.installData = data;
075        if (data.localeISO3 != null)
076        {
077            this.locale = data.localeISO3;
078        }
079        else
080        {
081            // try to figure out ourself
082            this.locale = installData.xmlData.getAttribute("langpack", "eng");
083        }
084    }
085
086    /**
087     * Create the resource manager.
088     * 
089     * This method should be called only once. If it is called a second time, the already existing
090     * instance is returned. The resource manager should be called <b>after</b> the language has
091     * been set in {@link AutomatedInstallData#localeISO3}
092     * 
093     * @param data the installation information
094     * @return the created instance
095     */
096    public static ResourceManager create(AutomatedInstallData data)
097    {
098        if (ResourceManager.instance == null) ResourceManager.instance = new ResourceManager(data);
099
100        return ResourceManager.instance;
101    }
102
103    /**
104     * Return the resource manager.
105     * 
106     * @return the resource manager instance, null if no instance has been created
107     */
108    public static ResourceManager getInstance()
109    {
110        return ResourceManager.instance;
111    }
112
113    /**
114     * This method is used to get the language dependent path of the given resource. If there is a
115     * resource for the current language the path of the language dependen resource is returnd. If
116     * there's no resource for the current lanuage the default path is returned.
117     * 
118     * @param resource Resource to load language dependen
119     * @return the language dependent path of the given resource
120     * @throws ResourceNotFoundException If the resource is not found
121     */
122    private String getLanguageResourceString(String resource) throws ResourceNotFoundException
123    {
124        InputStream in;
125        String resourcePath = this.resourceBasePath + resource + "_" + this.locale;
126        in = ResourceManager.class.getResourceAsStream(resourcePath);
127        if (in != null)
128            return resourcePath;
129        else
130        {
131            // if there's no language dependent resource found
132            resourcePath = this.resourceBasePath + resource;
133            in = ResourceManager.class.getResourceAsStream(resourcePath);
134            if (in != null)
135                return resourcePath;
136            else
137                throw new ResourceNotFoundException("Can not find Resource " + resource
138                        + " for language " + this.locale);
139        }
140    }
141
142    /**
143     * Returns an InputStream contains the given Resource The Resource is loaded language dependen
144     * by the informations from <code>this.locale</code> If there is no Resource for the current
145     * language found, the default Resource is given.
146     * 
147     * @param resource The resource to load
148     * @return an InputStream contains the requested resource
149     * @exception ResourceNotFoundException Description of the Exception
150     * @throws ResourceManager.ResourceNotFoundException thrown if there is no resource found
151     */
152    public InputStream getInputStream(String resource) throws ResourceNotFoundException
153    {
154        String resourcepath = this.getLanguageResourceString(resource);
155        // System.out.println ("reading resource "+resourcepath);
156        return ResourceManager.class.getResourceAsStream(resourcepath);
157    }
158
159    /**
160     * Returns a URL refers to the given Resource
161     * 
162     * @param resource the resource to load
163     * @return A languagedependen URL spezifies the requested resource
164     * @exception ResourceNotFoundException Description of the Exception
165     * @throws ResourceManager.ResourceNotFoundException thrown if there is no resource found
166     */
167    public URL getURL(String resource) throws ResourceNotFoundException
168    {
169        try
170        {
171            return this.getClass().getResource(
172                    this.getLanguageResourceString(resource + "_" + installData.localeISO3));
173        }
174        catch (Exception ex)
175        {
176            return this.getClass().getResource(this.getLanguageResourceString(resource));
177        }
178    }
179
180    /**
181     * Returns a text resource from the jar file. The resource is loaded by
182     * ResourceManager#getResource and then converted into text.
183     * 
184     * @param resource - a text resource to load
185     * @return a String contains the text of the resource
186     * @throws ResourceNotFoundException if the resource can not be found
187     * @throws IOException if the resource can not be loaded
188     */
189    // Maybe we can add a text parser for this method
190    public String getTextResource(String resource) throws ResourceNotFoundException, IOException
191    {
192        InputStream in = null;
193        try
194        {
195            in = this.getInputStream(resource + "_" + this.installData.localeISO3);
196        }
197        catch (Exception ex)
198        {
199            in = this.getInputStream(resource);
200        }
201
202        ByteArrayOutputStream infoData = new ByteArrayOutputStream();
203        byte[] buffer = new byte[5120];
204        int bytesInBuffer;
205        while ((bytesInBuffer = in.read(buffer)) != -1)
206            infoData.write(buffer, 0, bytesInBuffer);
207
208        return infoData.toString();
209    }
210
211    /**
212     * Returns a laguage dependent ImageIcon for the given Resource
213     * 
214     * @param resource resrouce of the Icon
215     * @return a ImageIcon loaded from the given Resource
216     * @throws ResourceNotFoundException thrown when the resource can not be found
217     * @throws IOException if the resource can not be loaded
218     */
219    public ImageIcon getImageIconResource(String resource) throws ResourceNotFoundException,
220            IOException
221    {
222        return new ImageIcon(this.getURL(resource));
223    }
224
225    /**
226     * Sets the locale for the resourcefiles. The locale is taken from
227     * InstallData#installData#getAttribute("langpack") If there is no language set, the default
228     * language is english.
229     * 
230     * @param locale of the resourcefile
231     */
232    public void setLocale(String locale)
233    {
234        this.locale = locale;
235    }
236
237    /**
238     * Returns the locale for the resourcefiles. The locale is taken from
239     * InstallData#installData#getAttribute("langpack") If there is no language set, the default
240     * language is english.
241     * 
242     * @return the current language
243     */
244    public String getLocale()
245    {
246        return this.locale;
247    }
248}