/* LanguageTool, a natural language style checker * Copyright (C) 2006 Daniel Naber (http://www.danielnaber.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ package de.danielnaber.languagetool.databroker; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.security.Permission; import de.danielnaber.languagetool.JLanguageTool; /** * Responsible for getting any items from the grammar checker's resource * directories. This default data broker assumes that they are accessible * directly via class-path and the directory names are like specified in: * * *

* * If you'd like to determine another resource directory location this default * data broker provides proper methods. * Assuming your {@code /rules} and {@code /resource} directories are accessible * via class-path with following path information: * *

* * In this case you have to invoke the methods * {@link ResourceDataBroker#setRulesDir(String)} and * {@link ResourceDataBroker#setResourceDir(String)} with following arguments: * * *

* * Make sure that you never obtain any grammar checker resources by calling * {@code Object.class.getResource(String)} or {@code * Object.class.getResourceAsStream(String)} directly. If you would like to * obtain something from these directories do always use * {@link JLanguageTool#getDataBroker()} which provides proper methods for * reading the directories above. *

* * For example, if you want to get the {@link URL} of {@code * /rules/de/grammar.xml} just invoke * {@link ResourceDataBroker#getFromRulesDirAsUrl(String)} and pass {@code * /de/grammar.xml} as a string. Note: The {@code /rules} directory's name isn't * passed, because its name might have changed. The same usage does apply for the * {@code /resource} directory. * * @see ResourceDataBroker * @author PAX * @since 1.0.1 */ public class DefaultResourceDataBroker implements ResourceDataBroker { /** * The directory's name of the grammar checker's resource directory. The * default value equals {@link ResourceDataBroker#RESOURCE_DIR}. */ protected String resourceDir; /** * The directory's name of the grammar checker's rules directory. The * default value equals {@link ResourceDataBroker#RULES_DIR}. */ protected String rulesDir; /** * Instantiates this data broker with the default resource directory names * as specified in: * *

*/ public DefaultResourceDataBroker() { this(ResourceDataBroker.RESOURCE_DIR, ResourceDataBroker.RULES_DIR); } /** * Instantiates this data broker with the passed resource directory names. * * @param resourceDir * The directory's name of the grammar checker's resource * directory. The default value equals * {@link ResourceDataBroker#RESOURCE_DIR}. * @param rulesDir * The directory's name of the grammar checker's rules directory. * The default value equals * {@link ResourceDataBroker#RULES_DIR}. */ public DefaultResourceDataBroker(final String resourceDir, final String rulesDir) { this.setResourceDir(resourceDir); this.setRulesDir(rulesDir); } /** * See: * {@link ResourceDataBroker#getFromResourceDirAsStream(java.lang.String)} * * @param path * The relative path to the item inside of the {@code /resource} * directory. Please start your path information with {@code /} * because it will be concatenated with the directory's name: * /resource/yourpath. * @return An {@link InputStream} object to the requested item or {@code * null} if it wasn't found. */ @Override public InputStream getFromResourceDirAsStream(final String path) { final String completePath = this.getCompleteResourceUrl(path); return ResourceDataBroker.class.getResourceAsStream(completePath); } /** * See: * {@link ResourceDataBroker#getFromResourceDirAsUrl(java.lang.String)} * * @param path * The relative path to the item inside of the {@code /resource} * directory. Please start your path information with {@code /} * because it will be concatenated with the directory's name: * /resource/yourpath. * @return An {@link URL} object to the requested item or {@code null} if it * wasn't found. */ @Override public URL getFromResourceDirAsUrl(final String path) { final String completePath = this.getCompleteResourceUrl(path); return getFixedJarURL(ResourceDataBroker.class.getResource(completePath)); } /** * Concatenates the passed resource path with the currently set {@code * resource} directory path. * * @param path * The relative path to a resource item inside of the {@code * resource} directory. * @return The full relative path to the resource including the path to the * {@code resource} directory. */ private String getCompleteResourceUrl(final String path) { final StringBuffer completePath = new StringBuffer(this.getResourceDir()); if (!this.getResourceDir().endsWith("/") && !(path.charAt(0)=='/')) { completePath.append('/'); } if (this.getResourceDir().endsWith("/") && (path.charAt(0)=='/') && path.length() > 1) { completePath.append(path.substring(1)); } else { completePath.append(path); } return completePath.toString(); } /** * See: * {@link ResourceDataBroker#getFromRulesDirAsStream(java.lang.String)} * * @param path * The relative path to the item inside of the {@code /rules} * directory. Please start your path information with {@code /} * because it will be concatenated with the directory's name: * /rules/yourpath. * @return An {@link InputStream} object to the requested item or {@code * null} if it wasn't found. */ @Override public InputStream getFromRulesDirAsStream(final String path) { final StringBuffer completePath = this.getCompleteRulesUrl(path); return ResourceDataBroker.class.getResourceAsStream(completePath.toString()); } /** * See: {@link ResourceDataBroker#getFromRulesDirAsUrl(java.lang.String)} * * @param path * The relative path to the item inside of the {@code /rules} * directory. Please start your path information with {@code /} * because it will be concatenated with the directory's name: * /rules/yourpath. * @return An {@link URL} object to the requested item or {@code null} if it * wasn't found. */ @Override public URL getFromRulesDirAsUrl(final String path) { final StringBuffer completePath = this.getCompleteRulesUrl(path); return getFixedJarURL(ResourceDataBroker.class.getResource(completePath.toString())); } /** * Concatenates the passed resource path with the currently set {@code * rules} directory path. * * @param path * The relative path to a resource item inside of the {@code * rules} directory. * @return The full relative path to the resource including the path to the * {@code rules} directory. */ private StringBuffer getCompleteRulesUrl(final String path) { final StringBuffer completePath = new StringBuffer(this.getRulesDir()); if (!this.getRulesDir().endsWith("/") && !(path.charAt(0)=='/')) { completePath.append('/'); } if (this.getRulesDir().endsWith("/") && (path.charAt(0)=='/') && path.length() > 1) { completePath.append(path.substring(1)); } else { completePath.append(path); } return completePath; } /** * @return The directory's name of the grammar checker's resource directory. * The default value equals * {@link ResourceDataBroker#RESOURCE_DIR}. */ @Override public String getResourceDir() { return this.resourceDir; } /** * @param resourceDir * The directory's name of the grammar checker's resource * directory. The default value was * {@link ResourceDataBroker#RESOURCE_DIR}. Please let this * string start with {@code '/'} and use this character as path * separator. Don't set this character to the string's end. Valid * example value: {@code /subdir/furtherdir/resourcedir}. */ @Override public void setResourceDir(final String resourceDir) { this.resourceDir = (resourceDir == null) ? "" : resourceDir; } /** * @return The directory's name of the grammar checker's rules directory. * The default value equals {@link ResourceDataBroker#RULES_DIR}. */ @Override public String getRulesDir() { return this.rulesDir; } /** * @param rulesDir * The directory's name of the grammar checker's rules directory. * The default value was {@link ResourceDataBroker#RULES_DIR}. * Please let this string start with {@code '/'} and use this * character as path separator. Don't set this character to the * string's end. Valid example value: {@code * /subdir/furtherdir/rulesdir}. */ @Override public void setRulesDir(final String rulesDir) { this.rulesDir = (rulesDir == null) ? "" : rulesDir; } /** * Fixes the getResource bug if you want to obtain any resource from a JAR file under Java * 1.5.0_16 Webstart. (Workaround by {@code mevanclark} from http://forums.sun.com) * * @param url The {@link URL} to be fixed. * @return The fixed version if necessary. */ private static URL getFixedJarURL(URL url) { if (url == null) { return url; } final String originalURLProtocol = url.getProtocol(); if (!"jar".equalsIgnoreCase(originalURLProtocol)) { return url; } final String originalURLString = url.toString(); final int bangSlashIndex = originalURLString.indexOf("!/"); if (bangSlashIndex > -1) { return url; } final String originalURLPath = url.getPath(); final URLConnection urlConnection; try { urlConnection = url.openConnection(); if (urlConnection == null) { throw new IOException("urlConnection is null"); } } catch (IOException e) { return url; } final Permission urlConnectionPermission; try { urlConnectionPermission = urlConnection.getPermission(); if (urlConnectionPermission == null) { throw new IOException("urlConnectionPermission is null"); } } catch (IOException e) { return url; } final String urlConnectionPermissionName = urlConnectionPermission.getName(); if (urlConnectionPermissionName == null) { return url; } final File file = new File(urlConnectionPermissionName); if (!file.exists()) { return url; } try { final String newURLStr = "jar:" + file.toURI().toURL().toExternalForm() + "!/" + originalURLPath; url = new URL(newURLStr); } catch (MalformedURLException e) { return url; } return url; } }