Java tutorial
/* * Copyright (C) 2008 John-Paul.Stanford <dev@stanwood.org.uk> * * 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 org.stanwood.media.setup; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.stanwood.media.Controller; import org.stanwood.media.actions.ActionException; import org.stanwood.media.actions.IAction; import org.stanwood.media.actions.rename.PatternMatcher; import org.stanwood.media.actions.rename.RenameAction; import org.stanwood.media.extensions.ExtensionException; import org.stanwood.media.extensions.ExtensionInfo; import org.stanwood.media.model.Mode; import org.stanwood.media.progress.IProgressMonitor; import org.stanwood.media.progress.SubMonitor; import org.stanwood.media.source.ISource; import org.stanwood.media.source.SourceException; import org.stanwood.media.source.xbmc.XBMCSource; import org.stanwood.media.store.IStore; import org.stanwood.media.store.StoreException; import org.stanwood.media.store.db.FileDatabaseStore; import org.stanwood.media.store.mp4.MP4ITunesStore; import org.stanwood.media.util.FileHelper; import org.stanwood.media.xml.XMLParser; import org.stanwood.media.xml.XMLParserException; import org.stanwood.media.xml.XMLParserNotFoundException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; /** * This is used to parse the XML configuration files. These are used to tell the * application which stores and sources should be used. * Strings in config file can contain variables which get evaulated with the configuration is read. */ public class ConfigReader extends BaseConfigReader { /** Default file name of config file */ public static final String CONFIG_NAME = "mediamanager-conf.xml"; //$NON-NLS-1$ private static final String SCHEMA_NAME = "MediaManager-Config-2.2.xsd"; //$NON-NLS-1$ private final static Log log = LogFactory.getLog(ConfigReader.class); private final static String DEFAULT_EXTS[] = new String[] { "avi", "mkv", "mov", "mpg", "mpeg", "mp4", "m4v", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$//$NON-NLS-5$//$NON-NLS-6$//$NON-NLS-7$ "srt", "sub", "divx" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ /** Default TV file rename patter */ public final static String DEFAULT_TV_FILE_PATTERN = "%n/Season %s/%sx%e - %t{ %d}.%x"; //$NON-NLS-1$ /** Default FILM file rename patter */ public final static String DEFAULT_FILM_FILE_PATTERN = "%t{ (%y)}{ Part %p}.%x"; //$NON-NLS-1$ private final static String DEFAULT_XBMC_ADDON_DIR = "http://mirrors.xbmc.org/addons/eden"; //$NON-NLS-1$ /** The default location to store configuration */ private static final File DEFAULT_MEDIA_CONFIG_DIR = new File(FileHelper.HOME_DIR, ".mediaManager"); //$NON-NLS-1$ private InputStream is; private List<MediaDirConfig> mediaDir; private List<WatchDirConfig> watchDirs; private Map<String, DBResource> databaseResources = new HashMap<String, DBResource>(); private File xbmcAddonDir; private Locale xbmcLocale = Locale.ENGLISH; private List<Plugin> plugins = new ArrayList<Plugin>(); private File configDir; private File nativeFolder; private String xbmcAddonSite = DEFAULT_XBMC_ADDON_DIR; private SeenDatabaseConfig seenDBConfig; /** The default strip tokens */ public final static List<Pattern> DEFAULT_STRIP_TOKENS; static { DEFAULT_STRIP_TOKENS = new ArrayList<Pattern>(); DEFAULT_STRIP_TOKENS.add(Pattern.compile("dvdrip", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("xvid", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("proper", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("ac3", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("1080p", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("720p", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("Blueray", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("Bluray", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("x264", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("Ntsc", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ DEFAULT_STRIP_TOKENS.add(Pattern.compile("pal", Pattern.CASE_INSENSITIVE)); //$NON-NLS-1$ } /** * The constructor used to create a instance of the configuration reader * @param is The configuration file input stream */ public ConfigReader(InputStream is) { this.is = is; } /** * This will parse the configuration in the XML configuration file and store the * results in this class. * @throws ConfigException Thrown if their is a problem parsing the file */ public void parse() throws ConfigException { try { if (log.isDebugEnabled()) { log.debug("Parsing configuration"); //$NON-NLS-1$ } Document doc = XMLParser.parse(is, SCHEMA_NAME); parseGlobal(doc); parseXBMCSettings(doc); parseMediaDirs(doc); parseWatchDirs(doc); parsePlguins(doc); parseResources(doc); parseSeenDatabase(doc); } catch (XMLParserException e) { throw new ConfigException(Messages.getString("UNABLE_PARSE_CONFIG"), e); //$NON-NLS-1$ } } private void parseSeenDatabase(Document doc) throws XMLParserException, ConfigException { if (selectSingleNode(doc, "/mediaManager/seenDatabase") != null) { //$NON-NLS-1$ SeenDatabaseConfig seenDBConfig = new SeenDatabaseConfig(); for (Node node : selectNodeList(doc, "/mediaManager/seenDatabase")) { //$NON-NLS-1$ Element seenDBNode = (Element) node; String resourceId = seenDBNode.getAttribute("resourceId"); //$NON-NLS-1$ if (resourceId.length() > 0) { seenDBConfig.setResourceId(resourceId); } } this.seenDBConfig = seenDBConfig; } else { this.seenDBConfig = null; } } private void writeSeenDatabase(StringBuilder document, IProgressMonitor progress) { if (seenDBConfig != null) { document.append(" <seenDatabase"); //$NON-NLS-1$ if (seenDBConfig.getResourceId() != null) { document.append(" resourceId=\"" + seenDBConfig.getResourceId() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } document.append(" />"); //$NON-NLS-1$ } } private void writeWatchDirs(StringBuilder document, IProgressMonitor progress) throws XMLParserException { for (WatchDirConfig dir : watchDirs) { document.append(" <watchDirectory"); //$NON-NLS-1$ document.append(" directory=\"" + dir.getWatchDir().getAbsolutePath() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ document.append(" />"); //$NON-NLS-1$ } } private void writeMediaDirs(StringBuilder document, IProgressMonitor progress) throws XMLParserException { for (MediaDirConfig dir : mediaDir) { document.append(" <mediaDirectory"); //$NON-NLS-1$ document.append(" directory=\"" + dir.getMediaDir().getAbsolutePath() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ document.append(" mode=\"" + dir.getMode() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ if (dir.isDefaultForMode()) { document.append(" default=\"true\""); //$NON-NLS-1$ } document.append(" pattern=\"" + dir.getPattern() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ document.append(" ignoreSeen=\"" + dir.getIgnoreSeen() + "\">" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ if (dir.getIgnorePatterns() != null) { for (Pattern p : dir.getIgnorePatterns()) { document.append(" <ignore>" + p.pattern() + "</ignore>" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ } } if (dir.getStripTokens() != null) { if (dir.getStripTokens() != DEFAULT_STRIP_TOKENS) { for (Pattern p : dir.getStripTokens()) { document.append("<strip>" + p.pattern() + "</strip>" + FileHelper.LS); //$NON-NLS-1$//$NON-NLS-2$ } } } if (dir.getExtensions().size() > 0 && !Arrays.equals(dir.getExtensions().toArray(new String[0]), DEFAULT_EXTS)) { document.append(" <extensions>" + FileHelper.LS); //$NON-NLS-1$ for (String ext : dir.getExtensions()) { document.append(" <extension>" + ext + "</extension>" + FileHelper.LS); //$NON-NLS-1$//$NON-NLS-2$ } document.append(" </extensions>" + FileHelper.LS); //$NON-NLS-1$ } if (dir.getSources().size() > 0) { document.append(" <sources>" + FileHelper.LS); //$NON-NLS-1$ for (SourceConfig source : dir.getSources()) { document.append(" <source"); //$NON-NLS-1$ witeBaseMediaDirSubItem(document, source); document.append(" </source>"); //$NON-NLS-1$ } document.append(" </sources>" + FileHelper.LS); //$NON-NLS-1$ } if (dir.getStores().size() > 0) { document.append(" <stores>" + FileHelper.LS); //$NON-NLS-1$ for (StoreConfig store : dir.getStores()) { document.append(" <store"); //$NON-NLS-1$ witeBaseMediaDirSubItem(document, store); document.append(" </store>"); //$NON-NLS-1$ } document.append(" </stores>" + FileHelper.LS); //$NON-NLS-1$ } if (dir.getActions().size() > 0) { document.append(" <actions>" + FileHelper.LS); //$NON-NLS-1$ for (ActionConfig action : dir.getActions()) { document.append(" <action"); //$NON-NLS-1$ witeBaseMediaDirSubItem(document, action); document.append(" </action>"); //$NON-NLS-1$ } document.append(" </actions>" + FileHelper.LS); //$NON-NLS-1$ } document.append(" </mediaDirectory>" + FileHelper.LS); //$NON-NLS-1$ progress.worked(1); } } protected void witeBaseMediaDirSubItem(StringBuilder document, BaseMediaDirSubItem subItem) { document.append(" id=\"" + subItem.getID() + "\""); //$NON-NLS-1$//$NON-NLS-2$ document.append(">" + FileHelper.LS); //$NON-NLS-1$ if (subItem.getParams().entrySet().size() > 0) { for (Entry<String, String> e : subItem.getParams().entrySet()) { document.append(" <param"); //$NON-NLS-1$ document.append(" name=\"" + e.getKey() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ document.append(" value=\"" + e.getValue() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ document.append("/>" + FileHelper.LS); //$NON-NLS-1$ } } } private void writeDBResources(StringBuilder document, SubMonitor progress) { if (databaseResources.size() > 0) { document.append(" <resources>" + FileHelper.LS); //$NON-NLS-1$ for (Entry<String, DBResource> e : databaseResources.entrySet()) { DBResource resource = e.getValue(); document.append(" <databaseResource id=\"" + e.getKey() + "\">" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ document.append(" <url>" + resource.getUrl() + "</url>" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ if (resource.getUsername() != null) { document.append(" <username>" + resource.getUsername() + "</username>" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ } if (resource.getPassword() != null) { document.append(" <password>" + resource.getPassword() + "</password>" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ } document.append(" <dialect>" + resource.getDialect() + "</dialect>" + FileHelper.LS); //$NON-NLS-1$//$NON-NLS-2$ if (resource.getSchemaCheck() != null) { document.append(" <schemaCheck>" + resource.getSchemaCheck().getValue() + "</schemaCheck>" //$NON-NLS-1$//$NON-NLS-2$ + FileHelper.LS); } document.append(" </databaseResource>" + FileHelper.LS); //$NON-NLS-1$ } document.append(" </resources>" + FileHelper.LS); //$NON-NLS-1$ } } private void parseResources(Document doc) throws XMLParserException, ConfigException { if (log.isDebugEnabled()) { log.debug("Parsing resources"); //$NON-NLS-1$ } for (Node node : selectNodeList(doc, "/mediaManager/resources/databaseResource")) { //$NON-NLS-1$ Element dbRsourceNode = (Element) node; DBResource dbResource = new DBResource(); String id = dbRsourceNode.getAttribute("id"); //$NON-NLS-1$ if (log.isDebugEnabled()) { log.debug("Parsing database resource resources: " + id); //$NON-NLS-1$ } if (id.length() == 0) { throw new ConfigException(Messages.getString("ConfigReader.DATABASE_ID_EMPTY")); //$NON-NLS-1$ } if (databaseResources.containsKey(id)) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.DATABASE_ID_NOT_UNIQUE"), id)); //$NON-NLS-1$ } dbResource.setDialect(getStringFromXML(dbRsourceNode, "dialect/text()")); //$NON-NLS-1$ dbResource.setUsername(getStringFromXMLOrNull(dbRsourceNode, "username/text()")); //$NON-NLS-1$ dbResource.setPassword(getStringFromXMLOrNull(dbRsourceNode, "password/text()")); //$NON-NLS-1$ dbResource.setUrl(getStringFromXML(dbRsourceNode, "url/text()")); //$NON-NLS-1$ dbResource.setResourceId(id); String schemaCheck = getStringFromXMLOrNull(dbRsourceNode, "schemaCheck/text()"); //$NON-NLS-1$ if (schemaCheck != null) { SchemaCheck sc = SchemaCheck.fromValue(schemaCheck); if (sc == null) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.InvalidValue"), schemaCheck)); //$NON-NLS-1$ } dbResource.setSchemaCheck(sc); } databaseResources.put(id, dbResource); } } private void parseMediaDirs(Document doc) throws XMLParserException, ConfigException { List<MediaDirConfig> dirConfigs = new ArrayList<MediaDirConfig>(); for (Node node : selectNodeList(doc, "/mediaManager/mediaDirectory")) { //$NON-NLS-1$ Element dirNode = (Element) node; MediaDirConfig dirConfig = new MediaDirConfig(); File dir = new File(parseString(dirNode.getAttribute("directory"))); //$NON-NLS-1$ if (!dir.exists()) { throw new ConfigException(MessageFormat.format( Messages.getString("ConfigReader.UNABLE_FIND_ROOT_MEDIA_DIR"), dir.getAbsolutePath())); //$NON-NLS-1$ } dirConfig.setMediaDir(dir); boolean defaultForMode = false; if (dirNode.getAttribute("default").equals("true")) { //$NON-NLS-1$//$NON-NLS-2$ defaultForMode = true; } dirConfig.setDefaultForMode(defaultForMode); String strMode = dirNode.getAttribute("mode").toUpperCase(); //$NON-NLS-1$ Mode mode; try { mode = Mode.valueOf(strMode); } catch (IllegalArgumentException e) { throw new ConfigException(MessageFormat.format(Messages.getString("ConfigReader.KNOWN_MODE"), //$NON-NLS-1$ strMode, dir.getAbsolutePath(), Mode.modeList())); } String pattern = dirNode.getAttribute("pattern").trim(); //$NON-NLS-1$ if (pattern.length() == 0) { pattern = DEFAULT_TV_FILE_PATTERN; if (mode == Mode.FILM) { pattern = DEFAULT_FILM_FILE_PATTERN; } log.warn(MessageFormat.format(Messages.getString("ConfigReader.NO_PATTERN"), pattern)); //$NON-NLS-1$ } else { if (!PatternMatcher.validPattern(pattern)) { throw new ConfigException(MessageFormat.format( Messages.getString("ConfigReader.INVALID_PATTERN"), pattern, dir.getAbsolutePath())); //$NON-NLS-1$ } } String ignoreSeenValue = dirNode.getAttribute("ignoreSeen"); //$NON-NLS-1$ boolean ignoreSeen = false; if (ignoreSeenValue != null && ignoreSeenValue.length() > 0) { ignoreSeen = Boolean.parseBoolean(ignoreSeenValue); } String name = dirNode.getAttribute("name").trim(); //$NON-NLS-1$ if (name.equals("")) { //$NON-NLS-1$ name = null; } dirConfig.setName(name); dirConfig.setPattern(pattern); dirConfig.setMode(mode); dirConfig.setIgnoreSeen(ignoreSeen); dirConfig.setSources(readSources(node, mode)); dirConfig.setStores(readStores(node, mode)); dirConfig.setActions(readActions(node, mode)); List<String> exts = new ArrayList<String>(); for (Node extNode : selectNodeList(node, "extensions/extension/text()")) { //$NON-NLS-1$ exts.add(extNode.getNodeValue()); } if (exts.size() == 0) { for (String ext : DEFAULT_EXTS) { exts.add(ext); } } dirConfig.setExtensions(exts); parseIgnorePatterns(node, dirConfig); parseStripPatterns(node, dirConfig); dirConfigs.add(dirConfig); } this.mediaDir = dirConfigs; } private void parseWatchDirs(Document doc) throws XMLParserException, ConfigException { List<WatchDirConfig> watchDirs = new ArrayList<WatchDirConfig>(); for (Node node : selectNodeList(doc, "/mediaManager/watchDirectory")) { //$NON-NLS-1$ Element dirNode = (Element) node; WatchDirConfig dirConfig = new WatchDirConfig(); File dir = new File(parseString(dirNode.getAttribute("directory"))); //$NON-NLS-1$ if (!dir.exists()) { throw new ConfigException( MessageFormat.format("Unable to find watch directory ''{0}''", dir.getAbsolutePath())); //$NON-NLS-1$ } dirConfig.setWatchDir(dir); watchDirs.add(dirConfig); } this.watchDirs = watchDirs; } private void parseStripPatterns(Node dirNode, MediaDirConfig dirConfig) throws XMLParserException { List<Pattern> stripTokens = new ArrayList<Pattern>(); if (selectSingleNode(dirNode, "strip/text()") != null) { //$NON-NLS-1$ for (Node node : selectNodeList(dirNode, "strip/text()")) { //$NON-NLS-1$ stripTokens.add(Pattern.compile(node.getTextContent())); } dirConfig.setStripTokens(stripTokens); } else { dirConfig.setStripTokens(DEFAULT_STRIP_TOKENS); } } private void parseIgnorePatterns(Node dirNode, MediaDirConfig dirConfig) throws XMLParserException, ConfigException { List<Pattern> patterns = new ArrayList<Pattern>(); for (Node node : selectNodeList(dirNode, "ignore/text()")) { //$NON-NLS-1$ patterns.add(Pattern.compile(node.getTextContent())); } if (patterns.size() > 0) { dirConfig.setIgnorePatterns(patterns); } } /** * Used to get the configuration for a root media directory * @param directory the root media directory * @return The configuration * @throws ConfigException Thrown if the configuration can't be found */ public MediaDirConfig getMediaDirectory(File directory) throws ConfigException { for (MediaDirConfig c : mediaDir) { if (c.getMediaDir().equals(directory)) { return c; } } throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_FIND_MEDIA_DIR"), directory)); //$NON-NLS-1$ } /** * Used to read the sources from the configuration file * @param controller The media controller * @param dirConfig The media directory configuration * @return Thrown if their are any problems * @throws ConfigException Thrown if their are any problems */ public List<ISource> loadSourcesFromConfigFile(Controller controller, MediaDirConfig dirConfig) throws ConfigException { List<ISource> sources = new ArrayList<ISource>(); int num = 0; for (SourceConfig sourceConfig : dirConfig.getSources()) { String id = sourceConfig.getID(); try { ExtensionInfo<? extends ISource> sourceInfo = controller.getSourceInfo(id); if (sourceInfo == null) { StringBuilder sb = new StringBuilder(); for (ExtensionInfo<? extends ISource> si : controller.getAvalibaleSources()) { if (sb.length() > 0) { sb.append(", "); //$NON-NLS-1$ } sb.append(si.getId()); } throw new ConfigException(MessageFormat .format(Messages.getString("ConfigReader.UNABLE_FIND_SOURCE"), id, sb.toString())); //$NON-NLS-1$ } ISource source = sourceInfo.getExtension(controller, dirConfig, num++); if (sourceConfig.getParams() != null) { for (String key : sourceConfig.getParams().keySet()) { String value = sourceConfig.getParams().get(key); setParamOnSource(source, key, value); } } sources.add(source); } catch (ExtensionException e) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_ADD_SOURCE"), id), e); //$NON-NLS-1$ } } return sources; } /** * Used to read the stores from the configuration file * @param controller The media controller * @param dirConfig The media directory configuration * @return The stores * @throws ConfigException Thrown if their is any problems */ public List<IStore> loadStoresFromConfigFile(Controller controller, MediaDirConfig dirConfig) throws ConfigException { int num = 0; List<IStore> stores = new ArrayList<IStore>(); for (StoreConfig storeConfig : dirConfig.getStores()) { String id = storeConfig.getID(); try { ExtensionInfo<? extends IStore> storeInfo = controller.getStoreInfo(id); if (storeInfo == null) { StringBuilder sb = new StringBuilder(); for (ExtensionInfo<? extends IStore> si : controller.getAvalibaleStores()) { if (sb.length() > 0) { sb.append(", "); //$NON-NLS-1$ } sb.append(si.getId()); } throw new ConfigException(MessageFormat .format(Messages.getString("ConfigReader.UNABLE_FIND_STORE"), id, sb.toString())); //$NON-NLS-1$ } IStore store = storeInfo.getExtension(controller, dirConfig, num++); if (storeConfig.getParams() != null) { for (String key : storeConfig.getParams().keySet()) { String value = storeConfig.getParams().get(key); setParamOnStore(store, key, value); } } stores.add(store); } catch (IllegalArgumentException e) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_ADD_STORE"), id), e); //$NON-NLS-1$ } catch (ExtensionException e) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_ADD_STORE"), id), e); //$NON-NLS-1$ } } return stores; } /** * Used to read the actions from the configuration file * @param controller The media controller * @param dirConfig The media directory configuration * @return The actions * @throws ConfigException Thrown if their is any problems */ public List<IAction> loadActionsFromConfigFile(Controller controller, MediaDirConfig dirConfig) throws ConfigException { List<IAction> actions = new ArrayList<IAction>(); int num = 0; for (ActionConfig actionConfig : dirConfig.getActions()) { String id = actionConfig.getID(); try { ExtensionInfo<? extends IAction> actionInfo = controller.getActionInfo(id); if (actionInfo == null) { StringBuilder sb = new StringBuilder(); for (ExtensionInfo<? extends IAction> ai : controller.getAvalibaleActions()) { if (sb.length() > 0) { sb.append(", "); //$NON-NLS-1$ } sb.append(ai.getId()); } throw new ConfigException(MessageFormat .format(Messages.getString("ConfigReader.UNABLE_FIND_ACTION"), id, sb.toString())); //$NON-NLS-1$ } IAction action = actionInfo.getExtension(controller, dirConfig, num++); if (actionConfig.getParams() != null) { for (String key : actionConfig.getParams().keySet()) { String value = actionConfig.getParams().get(key); setParamOnAction(action, key, value); } } actions.add(action); } catch (IllegalArgumentException e) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_ADD_ACTION"), id), e); //$NON-NLS-1$ } catch (ExtensionException e) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_ADD_ACTION"), id), e); //$NON-NLS-1$ } } return actions; } private void setParamOnSource(ISource source, String key, String value) throws SourceException { source.setParameter(key, value); } private void setParamOnStore(IStore store, String key, String value) throws StoreException { store.setParameter(key, value); } private void setParamOnAction(IAction action, String key, String value) throws ActionException { action.setParameter(key, value); } /** * Used to get the directory where XBMC addons are installed. If one has not been specified in the configuration, then * a default on is used instead of $HOME/.mediaManager/xbmc/addons. * @return The XBMC addon directory * @throws ConfigException Thrown if their is a problem */ public File getXBMCAddonDir() throws ConfigException { if (xbmcAddonDir == null) { return getDefaultAddonDir(); } return xbmcAddonDir; } private File getDefaultAddonDir() throws ConfigException { File addonDir = new File(getConfigDir(), "xbmc" + File.separator + "addons"); //$NON-NLS-1$ //$NON-NLS-2$ if (!addonDir.exists()) { if (!addonDir.mkdirs() && !addonDir.exists()) { throw new ConfigException(MessageFormat .format(Messages.getString("ConfigReader.UNABLE_CREATE_XBMC_ADDON_DIR"), addonDir)); //$NON-NLS-1$ } } return addonDir; } /** * Get the location of the media directory * @return The location of the media directory * @throws ConfigException Thrown if their is a problem */ public File getConfigDir() throws ConfigException { if (configDir == null) { configDir = getDefaultConfigDir(); } return configDir; } /** * Used to get the default location of the media manager configuration directory * @return the default location of the media manager configuration directory * @throws ConfigException Thrown if their is a problem */ public static File getDefaultConfigDir() throws ConfigException { File dir = DEFAULT_MEDIA_CONFIG_DIR; if (!dir.exists()) { if (!dir.mkdirs() && !dir.exists()) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNABLE_CREATE_CONFIG_DIR"), dir)); //$NON-NLS-1$ } } return dir; } /** * Used to get the locale that should be used when fetching media information from XBMC Addons. * @return The locale */ public Locale getXBMCLocale() { return xbmcLocale; } private void writePlugins(StringBuilder document) { if (plugins.size() > 0) { document.append(" <plugins>" + FileHelper.LS); //$NON-NLS-1$ for (Plugin plugin : plugins) { if (plugin.getJar() != null) { document.append(" <plugin jar=\"" + plugin.getJar() + "\" class=\"" + plugin.getPluginClass() //$NON-NLS-1$//$NON-NLS-2$ + "\"/>"); //$NON-NLS-1$ } else { document.append(" <plugin class=\"" + plugin.getPluginClass() + "\"/>"); //$NON-NLS-1$ //$NON-NLS-2$ } } document.append(" </plugins>" + FileHelper.LS); //$NON-NLS-1$ } } private void parsePlguins(Node doc) throws XMLParserException { for (Node n : selectNodeList(doc, "/mediaManager/plugins/plugin")) { //$NON-NLS-1$ Element pluginEl = (Element) n; String strJar = pluginEl.getAttribute("jar"); //$NON-NLS-1$ String jar = null; if (strJar.length() > 0) { jar = parseString(strJar); } String clazz = parseString(pluginEl.getAttribute("class")); //$NON-NLS-1$ plugins.add(new Plugin(jar, clazz)); } } private void parseXBMCSettings(Node configNode) throws XMLParserException { Element node = (Element) selectSingleNode(configNode, "/mediaManager/XBMCAddons"); //$NON-NLS-1$ if (node != null) { String dir = parseString(node.getAttribute("directory")); //$NON-NLS-1$ if (dir.trim().length() > 0) { xbmcAddonDir = FileHelper.resolveRelativePaths(new File(dir)); } String locale = parseString(node.getAttribute("locale")); //$NON-NLS-1$ if (locale.trim().length() > 0) { xbmcLocale = new Locale(locale); } String addonSite = parseString(node.getAttribute("addonSite")); //$NON-NLS-1$ if (addonSite.trim().length() > 0) { xbmcAddonSite = addonSite; } } } private void writeXBMCSettings(StringBuilder document) throws ConfigException { StringBuilder subDoc = new StringBuilder(); if (xbmcAddonDir != null) { subDoc.append(" directory=\"" + xbmcAddonDir + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } if (!xbmcLocale.equals(Locale.ENGLISH)) { subDoc.append(" locale=\"" + xbmcLocale.getLanguage() + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } if (!xbmcAddonSite.equals(DEFAULT_XBMC_ADDON_DIR)) { subDoc.append(" addonSite=\"" + xbmcAddonSite + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } if (subDoc.length() > 0) { document.append(" <XBMCAddons"); //$NON-NLS-1$ document.append(subDoc); document.append("/>" + FileHelper.LS); //$NON-NLS-1$ } } private void parseGlobal(Document configNode) throws XMLParserException { Element node = (Element) selectSingleNode(configNode, "/mediaManager/global"); //$NON-NLS-1$ if (node != null) { try { String dir = parseString(getStringFromXML(node, "configDirectory/text()")); //$NON-NLS-1$ if (dir.trim().length() > 0) { configDir = FileHelper.resolveRelativePaths(new File(dir)); } } catch (XMLParserNotFoundException e) { // Ignore } try { String value = parseString(getStringFromXML(node, "native/text()")); //$NON-NLS-1$ if (value != null && !value.equals("")) { //$NON-NLS-1$ nativeFolder = FileHelper.resolveRelativePaths(new File(value)); } } catch (XMLParserNotFoundException e) { // Ignore } } } private void writeGlobalSettings(StringBuilder document) throws ConfigException { StringBuilder subDoc = new StringBuilder(); if (configDir != null && !configDir.equals(getDefaultConfigDir())) { subDoc.append( " <configDirectory>" + configDir.getAbsolutePath() + "</configDirectory>" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ } if (nativeFolder != null) { subDoc.append(" <native>" + nativeFolder.getAbsolutePath() + "</native>" + FileHelper.LS); //$NON-NLS-1$ //$NON-NLS-2$ } if (subDoc.length() > 0) { document.append(" <global>" + FileHelper.LS); //$NON-NLS-1$ document.append(subDoc); document.append(" </global>" + FileHelper.LS); //$NON-NLS-1$ } } private List<SourceConfig> readSources(Node configNode, Mode mode) throws XMLParserException { int num = 0; List<SourceConfig> sources = new ArrayList<SourceConfig>(); if (selectSingleNode(configNode, "sources") == null) { //$NON-NLS-1$ if (mode == Mode.FILM) { SourceConfig config = new SourceConfig(); config.setNumber(num++); config.setID(XBMCSource.class.getName() + "#metadata.themoviedb.org"); //$NON-NLS-1$ sources.add(config); config = new SourceConfig(); config.setNumber(num++); config.setID(XBMCSource.class.getName() + "#metadata.imdb.com"); //$NON-NLS-1$ sources.add(config); } else { SourceConfig config = new SourceConfig(); config.setNumber(num++); config.setID(XBMCSource.class.getName() + "#metadata.tvdb.com"); //$NON-NLS-1$ sources.add(config); } } else { for (Node sourceElement : selectNodeList(configNode, "sources/source")) { //$NON-NLS-1$ SourceConfig source = new SourceConfig(); source.setNumber(num); source.setID(((Element) sourceElement).getAttribute("id")); //$NON-NLS-1$ for (Node paramNode : selectNodeList(sourceElement, "param")) { //$NON-NLS-1$ String name = ((Element) paramNode).getAttribute("name"); //$NON-NLS-1$ String value = parseString(((Element) paramNode).getAttribute("value")); //$NON-NLS-1$ source.addParam(name, value); } sources.add(source); num++; } } return sources; } private List<StoreConfig> readStores(Node configNode, Mode mode) throws XMLParserException { int num = 0; List<StoreConfig> stores = new ArrayList<StoreConfig>(); if (selectSingleNode(configNode, "stores") == null) { //$NON-NLS-1$ StoreConfig config = new StoreConfig(); config.setNumber(num++); config.setID(MP4ITunesStore.class.getName()); stores.add(config); config = new StoreConfig(); config.setNumber(num++); config.setID(FileDatabaseStore.class.getName()); stores.add(config); } else { for (Node storeElement : selectNodeList(configNode, "stores/store")) { //$NON-NLS-1$ StoreConfig store = new StoreConfig(); store.setNumber(num); store.setID(((Element) storeElement).getAttribute("id")); //$NON-NLS-1$ for (Node paramNode : selectNodeList(storeElement, "param")) { //$NON-NLS-1$ String name = ((Element) paramNode).getAttribute("name"); //$NON-NLS-1$ String value = parseString(((Element) paramNode).getAttribute("value")); //$NON-NLS-1$ store.addParam(name, value); } stores.add(store); num++; } } return stores; } private List<ActionConfig> readActions(Node configNode, Mode mode) throws XMLParserException { int num = 0; List<ActionConfig> actions = new ArrayList<ActionConfig>(); if (selectSingleNode(configNode, "actions") == null) { //$NON-NLS-1$ ActionConfig config = new ActionConfig(); config.setNumber(num++); config.setID(RenameAction.class.getName()); actions.add(config); } else { for (Node storeElement : selectNodeList(configNode, "actions/action")) { //$NON-NLS-1$ ActionConfig action = new ActionConfig(); action.setNumber(num); action.setID(((Element) storeElement).getAttribute("id")); //$NON-NLS-1$ for (Node paramNode : selectNodeList(storeElement, "param")) { //$NON-NLS-1$ String name = ((Element) paramNode).getAttribute("name"); //$NON-NLS-1$ String value = parseString(((Element) paramNode).getAttribute("value")); //$NON-NLS-1$ action.addParam(name, value); } actions.add(action); num++; } } return actions; } /** * Used to get a list of plugins * @return a list of plugins */ public List<Plugin> getPlugins() { return plugins; } private String parseString(String input) { input = input.replaceAll("\\$HOME", FileHelper.HOME_DIR.getAbsolutePath()); //$NON-NLS-1$ return input; } /** * Used to the default configuration filename * @return The default configuration filename * @throws ConfigException Thrown if their are any problems */ public static File getDefaultConfigFile() throws ConfigException { File file = new File(ConfigReader.getDefaultConfigDir(), CONFIG_NAME); if (!file.exists()) { file = new File(File.separator + "etc" + File.separator + CONFIG_NAME); //$NON-NLS-1$ } if (!file.exists()) { file = new File(ConfigReader.getDefaultConfigDir(), CONFIG_NAME); try { FileHelper.copy(ConfigReader.class.getResourceAsStream("defaultConfig.xml"), file); //$NON-NLS-1$ } catch (IOException e) { throw new ConfigException( MessageFormat.format(Messages.getString("ConfigReader.UNALBE_CREATE_CONFIG_FILE"), file), //$NON-NLS-1$ e); } } return file; } /** * Used to get a list of media directory locations * @return Media directory locations */ public Collection<File> getMediaDirectories() { List<File> mediaDirs = new ArrayList<File>(); for (MediaDirConfig c : mediaDir) { mediaDirs.add(c.getMediaDir()); } return mediaDirs; } /** * Used to get the watched directory configuration information * @return The watched directories */ public Collection<WatchDirConfig> getWatchDirectories() { List<WatchDirConfig> mediaDirs = new ArrayList<WatchDirConfig>(); for (WatchDirConfig c : watchDirs) { mediaDirs.add(c); } return mediaDirs; } /** * Used to find the native folder. Null is returend if it could not be found * @return The native folder, or null if not found */ public File getNativeFolder() { if (nativeFolder == null) { String nativeDir = System.getenv("MM_NATIVE_DIR"); //$NON-NLS-1$ if (nativeDir != null && nativeDir.length() > 0) { return FileHelper.resolveRelativePaths(new File(nativeDir)); } } return nativeFolder; } /** * Used to get the addon site url * @return the addon site url */ public String getXBMCAddonSiteUrl() { return xbmcAddonSite; } /** * Write the configuration to a file * @param monitor The progress monitor * @param file File to save the configuration to * @throws ConfigException Thrown if their is a problem */ public void writeConfig(IProgressMonitor monitor, File file) throws ConfigException { SubMonitor progress = SubMonitor.convert(monitor, mediaDir.size() + 7); try { StringBuilder document = new StringBuilder(); document.append("<mediaManager>" + FileHelper.LS); //$NON-NLS-1$ writePlugins(document); progress.worked(1); writeXBMCSettings(document); progress.worked(1); writeGlobalSettings(document); progress.worked(1); writeMediaDirs(document, progress); progress.worked(1); writeWatchDirs(document, progress); progress.worked(1); writeDBResources(document, progress); progress.worked(1); writeSeenDatabase(document, progress); document.append("</mediaManager>" + FileHelper.LS); //$NON-NLS-1$ Document doc = XMLParser.strToDom(document.toString(), SCHEMA_NAME); XMLParser.writeXML(file, doc); progress.worked(1); } catch (Exception e) { throw new ConfigException(Messages.getString("ConfigReader.UNABLE_WRITE_CONFIG"), e); //$NON-NLS-1$ } finally { progress.done(); } } /** * Used to get the database resources * @return the database resources */ public Map<String, DBResource> getDatabaseResources() { return databaseResources; } /** * Used to get the seen database configuration. If none configured, then this returns NULL * @return The seen database configuration */ public SeenDatabaseConfig getSeenDatabase() { return seenDBConfig; } }