001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019
020package icy.plugin.classloader;
021
022import icy.file.FileUtil;
023import icy.network.NetworkUtil;
024import icy.plugin.classloader.exception.JclException;
025import icy.plugin.classloader.exception.ResourceNotFoundException;
026import icy.system.IcyExceptionHandler;
027
028import java.io.File;
029import java.io.IOException;
030import java.net.URISyntaxException;
031import java.net.URL;
032import java.util.logging.Level;
033import java.util.logging.Logger;
034
035/**
036 * Class that builds a local classpath by loading resources from different
037 * files/paths
038 * 
039 * @author Kamran Zafar
040 * @author Stephane Dallongeville
041 */
042public class ClasspathResources extends JarResources
043{
044    private static Logger logger = Logger.getLogger(ClasspathResources.class.getName());
045    private boolean ignoreMissingResources;
046
047    public ClasspathResources()
048    {
049        super();
050        ignoreMissingResources = Configuration.suppressMissingResourceException();
051    }
052
053    /**
054     * Attempts to load a remote resource (jars, properties files, etc)
055     * 
056     * @param url
057     */
058    protected void loadRemoteResource(URL url)
059    {
060        if (logger.isLoggable(Level.FINEST))
061            logger.finest("Attempting to load a remote resource.");
062
063        if (url.toString().toLowerCase().endsWith(".jar"))
064        {
065            try
066            {
067                loadJar(url);
068            }
069            catch (IOException e)
070            {
071                System.err.println("JarResources.loadJar(" + url + ") error:");
072                IcyExceptionHandler.showErrorMessage(e, false, true);
073            }
074            return;
075        }
076
077        if (entryUrls.containsKey(url.toString()))
078        {
079            if (!collisionAllowed)
080                throw new JclException("Resource " + url.toString() + " already loaded");
081
082            if (logger.isLoggable(Level.FINEST))
083                logger.finest("Resource " + url.toString() + " already loaded; ignoring entry...");
084            return;
085        }
086
087        if (logger.isLoggable(Level.FINEST))
088            logger.finest("Loading remote resource.");
089
090        entryUrls.put(url.toString(), url);
091    }
092
093    /**
094     * Loads and returns content the remote resource (jars, properties files, etc)
095     * 
096     * @throws IOException
097     */
098    protected byte[] loadRemoteResourceContent(URL url) throws IOException
099    {
100        final byte[] result = NetworkUtil.download(url.openStream());
101
102        if (result != null)
103            loadedSize += result.length;
104
105        return result;
106    }
107
108    /**
109     * Reads local and remote resources
110     * 
111     * @param url
112     */
113    protected void loadResource(URL url)
114    {
115        try
116        {
117            final File file = new File(url.toURI());
118            // Is Local
119            loadResource(file, FileUtil.getGenericPath(file.getAbsolutePath()));
120        }
121        catch (IllegalArgumentException iae)
122        {
123            // Is Remote
124            loadRemoteResource(url);
125        }
126        catch (URISyntaxException e)
127        {
128            throw new JclException("URISyntaxException", e);
129        }
130    }
131
132    /**
133     * Reads local resources from - Jar files - Class folders - Jar Library
134     * folders
135     * 
136     * @param path
137     */
138    protected void loadResource(String path)
139    {
140        if (logger.isLoggable(Level.FINEST))
141            logger.finest("Resource: " + path);
142
143        File fp = new File(path);
144
145        if (!fp.exists() && !ignoreMissingResources)
146            throw new JclException("File/Path does not exist");
147
148        loadResource(fp, FileUtil.getGenericPath(path));
149    }
150
151    /**
152     * Reads local resources from - Jar files - Class folders - Jar Library
153     * folders
154     * 
155     * @param fol
156     * @param packName
157     */
158    protected void loadResource(File fol, String packName)
159    {
160        // FILE
161        if (fol.isFile())
162        {
163            if (fol.getName().toLowerCase().endsWith(".jar"))
164            {
165                try
166                {
167                    loadJar(fol.toURI().toURL());
168                }
169                catch (IOException e)
170                {
171                    System.err.println("JarResources.loadJar(" + fol.getAbsolutePath() + ") error:");
172                    IcyExceptionHandler.showErrorMessage(e, false, true);
173                }
174            }
175            else
176                loadResourceInternal(fol, packName);
177        }
178        // DIRECTORY
179        else
180        {
181            if (fol.list() != null)
182            {
183                for (String f : fol.list())
184                {
185                    File fl = new File(fol.getAbsolutePath() + "/" + f);
186
187                    String pn = packName;
188
189                    if (fl.isDirectory())
190                    {
191
192                        if (!pn.equals(""))
193                            pn = pn + "/";
194
195                        pn = pn + fl.getName();
196                    }
197
198                    loadResource(fl, pn);
199                }
200            }
201        }
202    }
203
204    /**
205     * Loads the local resource.
206     */
207    protected void loadResourceInternal(File file, String pack)
208    {
209        String entryName = "";
210
211        if (pack.length() > 0)
212            entryName = pack + "/";
213        entryName += file.getName();
214
215        if (entryUrls.containsKey(entryName))
216        {
217            if (!collisionAllowed)
218                throw new JclException("Resource " + entryName + " already loaded");
219
220            if (logger.isLoggable(Level.WARNING))
221                logger.finest("Resource " + entryName + " already loaded; ignoring entry...");
222            return;
223        }
224
225        if (logger.isLoggable(Level.FINEST))
226            logger.finest("Loading resource: " + entryName);
227
228        try
229        {
230            entryUrls.put(entryName, file.toURI().toURL());
231        }
232        catch (Exception e)
233        {
234            if (logger.isLoggable(Level.SEVERE))
235                logger.finest("Error while loading: " + entryName);
236
237            System.err.println("JarResources.loadResourceInternal(" + file.getAbsolutePath() + ") error:");
238            IcyExceptionHandler.showErrorMessage(e, false, true);
239        }
240    }
241
242    @Override
243    protected void loadContent(String name, URL url) throws IOException
244    {
245        // JAR protocol
246        if (url.getProtocol().equalsIgnoreCase(("jar")))
247            super.loadContent(name, url);
248        // FILE protocol
249        else if (url.getProtocol().equalsIgnoreCase(("file")))
250        {
251            final byte[] content = loadResourceContent(url);
252            setResourceContent(name, content);
253        }
254        // try remote loading
255        else
256        {
257            final byte content[] = loadRemoteResourceContent(url);
258            setResourceContent(name, content);
259        }
260    }
261
262    /**
263     * Loads and returns the local resource content.
264     * 
265     * @throws IOException
266     */
267    protected byte[] loadResourceContent(URL url) throws IOException
268    {
269        final byte[] result = NetworkUtil.download(url.openStream());
270
271        if (result != null)
272            loadedSize += result.length;
273
274        return result;
275    }
276
277    /**
278     * Removes the loaded resource
279     * 
280     * @param resource
281     */
282    public void unload(String resource)
283    {
284        if (entryContents.containsKey(resource))
285        {
286            if (logger.isLoggable(Level.FINEST))
287                logger.finest("Removing resource " + resource);
288            entryContents.remove(resource);
289        }
290        else
291            throw new ResourceNotFoundException(resource, "Resource not found in local ClasspathResources");
292    }
293
294    public boolean isCollisionAllowed()
295    {
296        return collisionAllowed;
297    }
298
299    public void setCollisionAllowed(boolean collisionAllowed)
300    {
301        this.collisionAllowed = collisionAllowed;
302    }
303
304    public boolean isIgnoreMissingResources()
305    {
306        return ignoreMissingResources;
307    }
308
309    public void setIgnoreMissingResources(boolean ignoreMissingResources)
310    {
311        this.ignoreMissingResources = ignoreMissingResources;
312    }
313}