Java tutorial
/** * Kindle Launcher * GUI menu launcher for Kindle Touch * Copyright (C) 2011 Yifan Lu * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.yifanlu.Kindle; import com.amazon.ebook.util.log.LogMessage; import org.json.simple.parser.ParseException; import org.kxml2.io.KXmlParser; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.*; import java.util.ArrayList; /** * This class holds the functions for loading and parsing the XML configs from extensions. * * @author Yifan Lu * @version 1.0 */ public class ExtensionsLoader { private static final LogMessage LOADED_EXTENSION = new LogMessage("ExtensionLoad", new String[] { "name", "version", "author", "id" }); private static final LogMessage MENU_ATTRIBUTES = new LogMessage("MenuLoad", new String[] { "name", "value" }); private File mDirectory; /** * Create a new extension loader using "directory" as the base * * @param directory Where the extensions are located. Each extension must be in its own folder and contain config.xml. */ public ExtensionsLoader(File directory) { mDirectory = directory; } /** * This converts all the extensions into objects using information from their config.xml and returns an array. * * @return A list of extensions that are loaded or an empty list of no extension is loaded successfully. */ public ArrayList loadExtensions() { KXmlParser parser = new KXmlParser(); ArrayList extList = new ArrayList(); File[] extensions = mDirectory.listFiles(new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } }); int i; try { for (i = 0; i < extensions.length; i++) { File ext = extensions[i]; KindleLauncher.LOG.info("Loading: " + ext.getAbsolutePath()); File config = new File(ext, "config.xml"); Extension extObj = new Extension(); parser.setInput(new InputStreamReader(new FileInputStream(config))); parser.nextTag(); parser.require(XmlPullParser.START_TAG, null, "extension"); while (parser.nextTag() != XmlPullParser.END_TAG) { parser.require(XmlPullParser.START_TAG, null, null); String name = parser.getName(); if (name.equals("information")) parseInformation(parser, extObj); else if (name.equals("menus")) parseMenus(parser, extObj, ext); else //skip while (parser.next() != XmlPullParser.END_TAG || !parser.getName().equals(name)) ; // this one line does magic to skip all unrelated events parser.require(XmlPullParser.END_TAG, null, name); } parser.require(XmlPullParser.END_TAG, null, "extension"); parser.next(); parser.require(XmlPullParser.END_DOCUMENT, null, null); extList.add(extObj); KindleLauncher.LOG.info(LOADED_EXTENSION, new String[] { extObj.getName(), extObj.getVersion(), extObj.getAuthor(), extObj.getId() }, ""); } } catch (IOException e) { KindleLauncher.LOG.error("Error reading extension config. " + e.getMessage()); e.printStackTrace(); } catch (XmlPullParserException e) { KindleLauncher.LOG.error("Error parsing extension config. " + e.getMessage()); e.printStackTrace(); } catch (NullPointerException e) { KindleLauncher.LOG .error("Error parsing extension menu. Required attribute not found. " + e.getMessage()); e.printStackTrace(); } catch (ClassNotFoundException e) { KindleLauncher.LOG .error("Error parsing extension menu. Cannot find menu Java class. " + e.getMessage()); e.printStackTrace(); } catch (ClassCastException e) { KindleLauncher.LOG.error("Error parsing extension menu. " + e.getMessage()); e.printStackTrace(); } catch (InstantiationException e) { KindleLauncher.LOG .error("Error parsing extension menu. Cannot create object from Java class. " + e.getMessage()); e.printStackTrace(); } catch (IllegalAccessException e) { KindleLauncher.LOG .error("Error parsing extension menu. Cannot create object from Java class. " + e.getMessage()); e.printStackTrace(); } catch (ParseException e) { KindleLauncher.LOG.error("Error parsing extension menu. Cannot parse JSON menu. " + e.getMessage()); e.printStackTrace(); } return extList; } /** * This parses the "information" section of the config.xml file. This section contains information about the * extension. This information is currently unused, but may be useful in the future so it is recommended that * all extensions contain it. The format is * <p/> * <pre> * <information> * <name>Name of the plugin</name> * <version>Version of the plugin</version> * <author>Author of the plugin</author> * <id>Unique id of the plugin</id> * </information> * </pre> * * @param parser {@link org.kxml2.io.KXmlParser} * @param extObj The {@link Extension} object to fill. * @throws IOException if the config cannot be read cannot be accessed * @throws XmlPullParserException if the config is malformed */ protected void parseInformation(KXmlParser parser, Extension extObj) throws IOException, XmlPullParserException { while (parser.nextTag() != XmlPullParser.END_TAG) { parser.require(XmlPullParser.START_TAG, null, null); String name = parser.getName(); String text = parser.nextText(); if (name.equals("name")) extObj.setName(text); else if (name.equals("version")) extObj.setVersion(text); else if (name.equals("author")) extObj.setAuthor(text); else if (name.equals("id")) extObj.setId(text); parser.require(XmlPullParser.END_TAG, null, name); } } /** * This parses the "menus" section of the config.xml file. The "menus" section can contain one or more list of * menu options that are loaded by either JSON or Java. All menu options from each list are added to the main menu. * The format of the entries in config.xml for the menus section is * <p/> * <pre> * <menus> * <menu type="VALUE" jar="VALUE" dynamic="VALUE">TEXT</menu> * </menus> * </pre> * <p/> * Where type is either "java" or "json", jar is required only for "java" types and is the path to the Jar file * containing the Menuable class relative to config.xml, dynamic is required only for JSON types and tells the * loader to re-read the JSON file each time the menu is opened, and the text of the element is either the path * to the JSON menu file or the Java class to load. * * @param parser {@link org.kxml2.io.KXmlParser} * @param extObj The {@link Extension} object to fill. * @param extDir The path to the extension's directory * @throws IOException if the config cannot be read or the extension directory cannot be accessed * @throws XmlPullParserException if the config is malformed * @throws ClassNotFoundException if the menu type is Java and the class specified cannot be loaded * @throws IllegalAccessException if the menu type is Java and the class specified cannot be accessed * @throws InstantiationException if the menu type is Java and the class specified cannot be instantiated * @throws ParseException if the config file cannot be parsed correctly */ protected void parseMenus(KXmlParser parser, Extension extObj, File extDir) throws IOException, XmlPullParserException, ClassNotFoundException, IllegalAccessException, InstantiationException, ParseException { while (parser.nextTag() != XmlPullParser.END_TAG) { parser.require(XmlPullParser.START_TAG, null, "menu"); Menuable menu; boolean isJava = false; boolean isDynamic = false; String jarFile = null; int i = parser.getAttributeCount(); KindleLauncher.LOG.debug("Attributes: " + parser.getAttributeCount()); while (i-- > 0) { String name = parser.getAttributeName(i); String value = parser.getAttributeValue(i); if (name.equals("type")) isJava = value.equals("java"); else if (name.equals("dynamic")) isDynamic = value.equals("true"); else if (name.equals("jar")) jarFile = value; KindleLauncher.LOG.debug(MENU_ATTRIBUTES, new String[] { name, value }, ""); } String text = parser.nextText(); if (isJava) { JARClassLoader classLoader = JARClassLoader.getInstance(); classLoader.addJar(new File(extDir, jarFile)); Class cls = classLoader.loadClass(text); menu = (Menuable) cls.newInstance(); KindleLauncher.LOG.debug("Loaded class: " + text); } else { File jsonFile = new File(extDir, text); JSONMenu jsonMenu = new JSONMenu(jsonFile); jsonMenu.setDynamic(isDynamic); jsonMenu.parseJSONMenu(); menu = jsonMenu; KindleLauncher.LOG.debug("Loaded menu: " + jsonFile.getAbsolutePath()); } extObj.setMenu(menu); parser.require(XmlPullParser.END_TAG, null, "menu"); } } }