/* JAI-Ext - OpenSource Java Advanced Image Extensions Library * http://www.geo-solutions.it/ * Copyright 2014 GeoSolutions * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package it.geosolutions.jaiext; import it.geosolutions.jaiext.ConcurrentOperationRegistry.OperationItem; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StreamTokenizer; import java.net.URL; import java.text.MessageFormat; import java.util.Collections; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.media.jai.OperationDescriptor; import javax.media.jai.RegistryElementDescriptor; import javax.media.jai.RegistryMode; import javax.media.jai.registry.RenderedRegistryMode; /** * A class to parse the JAI registry file. * * @author Nicola Lagomarsini - GeoSolutions */ class RegistryFileParser { /** {@link Logger} used for Logging any exception or warning */ private static final Logger LOGGER = Logger.getLogger(RegistryFileParser.class.toString()); /** * Returns a map with the descriptors, factories from the <code>URL</code>. */ static Map<String, OperationItem> parseFile(ClassLoader cl, URL url) throws IOException { return (new RegistryFileParser(cl, url)).parseFile(); } /** Input {@link URL} for the registryFile */ private URL url; /** Input stream for the registryFile */ private InputStream is; /** {@link ClassLoader} used for loading the registryFile resources */ private ClassLoader classLoader; private BufferedReader reader; /** * Create a {@link RegistryFileParser} from an <code>URL</code> */ private RegistryFileParser(ClassLoader cl, URL url) throws IOException { this.is = url.openStream(); this.url = null; this.classLoader = cl; // Set up streamtokenizer reader = new BufferedReader(new InputStreamReader(is)); } // Aliases for backward compatibility private static String[][] aliases = { { "odesc", "descriptor" }, { "rif", "rendered" }, { "crif", "renderable" }, { "cif", "collection" }, }; /** * Map old keywords to the new keywords */ private String mapName(String key) { for (int i = 0; i < aliases.length; i++) if (key.equalsIgnoreCase(aliases[i][0])) return aliases[i][1]; return key; } /** * Create an instance given the class name. */ private Object getInstance(String className) { try { Class descriptorClass = null; String errorMsg = null; // Since the classes listed in the registryFile can // reside anywhere (core, ext, classpath or the specified // classloader) we have to try every place. // First try the specified classloader if (classLoader != null) { try { descriptorClass = Class.forName(className, true, classLoader); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); errorMsg = e.getMessage(); } } // Next try the callee classloader if (descriptorClass == null) { try { descriptorClass = Class.forName(className); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); errorMsg = e.getMessage(); } } // Then try the System classloader (because the specified // classloader might be null and the callee classloader // might be an ancestor of the SystemClassLoader if (descriptorClass == null) { try { descriptorClass = Class.forName(className, true, ClassLoader.getSystemClassLoader()); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); errorMsg = e.getMessage(); } } // If nothing is found an exception is reported if (descriptorClass == null) { registryFileError(errorMsg); return null; } return descriptorClass.newInstance(); } catch (Exception e) { registryFileError(e.getMessage()); LOGGER.log(Level.SEVERE, e.getMessage(), e); } return null; } /** * Parse the entire registry file and stores its informations inside a map. */ Map<String, OperationItem> parseFile() throws IOException { // Initialization of the map Map<String, OperationItem> operations = new HashMap<String, OperationItem>(); String[] keys; while ((keys = getNextLine()) != null) { RegistryMode mode; // Mapping of the key String key = mapName(keys[0]); // Selection of the descriptor if (key.equalsIgnoreCase("descriptor")) { RegistryElementDescriptor red = (RegistryElementDescriptor) getInstance(keys[1]); // Storing the information of the description only if it is an OperationDescriptor if (red != null && red instanceof OperationDescriptor) { OperationDescriptor desc = (OperationDescriptor) red; operations.put(desc.getName(), new OperationItem(desc)); } // If it is a rendered registry mode, then get the // factory object. } else if ((mode = RegistryMode.getMode(key)) != null) { Object factory = getInstance(keys[1]); if (mode.getName().equalsIgnoreCase(RenderedRegistryMode.MODE_NAME) && factory != null) { operations.get(keys[3]).setFactory(factory); } } else if (!(key.equalsIgnoreCase("registryMode") || key.equalsIgnoreCase("pref") || key .equalsIgnoreCase("productPref"))) { registryFileError("Can not parse line"); } } // If this was read in from an URL, we created the InputStream // and so we should close it. reader.close(); is.close(); return operations; } private String[] getNextLine() throws IOException { // TODO Auto-generated method stub String line = reader.readLine(); if (line != null) { if (line.isEmpty() || line.startsWith("#") || line.startsWith("\\s")) { return getNextLine(); } else { String[] split = line.split("\\s"); String[] corrected = new String[split.length]; int count = 0; for (int i = 0; i < split.length; i++) { if (!(split[i].equals("\\s") || split[i].isEmpty())) { corrected[count] = split[i]; count++; } } return corrected; } } else { return null; } } /** Boolean indicating that the header line has already been printed */ private boolean headerLinePrinted = false; /** * Print the line number and then print the passed in message. */ private void registryFileError(String msg) { if (!headerLinePrinted) { if (url != null) { errorMsg("Error while parsing JAI registry file " + url.getPath(), null); } headerLinePrinted = true; } if (msg != null) errorMsg(msg, null); } /** * Creates a <code>MessageFormat</code> object and set the <code>Locale</code> to default and formats the message */ private void errorMsg(String key, Object[] args) { MessageFormat mf = new MessageFormat(key); mf.setLocale(Locale.getDefault()); LOGGER.log(Level.SEVERE, mf.format(args)); } }