/******************************************************************************* * Copyright 2016 * Ubiquitous Knowledge Processing (UKP) Lab * Technische Universität Darmstadt * * 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 de.tudarmstadt.ukp.uby.resource; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.uima.fit.component.Resource_ImplBase; import org.apache.uima.fit.descriptor.ConfigurationParameter; import org.apache.uima.fit.descriptor.ExternalResourceLocator; import org.apache.uima.resource.ResourceInitializationException; import org.apache.uima.resource.ResourceSpecifier; import de.tudarmstadt.ukp.dkpro.core.api.parameter.ComponentParameters; import de.tudarmstadt.ukp.dkpro.core.api.resources.CasConfigurableProviderBase; import de.tudarmstadt.ukp.dkpro.core.api.resources.CompressionUtils; import de.tudarmstadt.ukp.dkpro.core.api.resources.ModelProviderBase; import de.tudarmstadt.ukp.lmf.api.Uby; import de.tudarmstadt.ukp.lmf.transform.DBConfig; /** * Locate an UBY object. * * @author Judith Eckle-Kohler * @author Richard Eckart de Castilho */ public class UbyResource extends Resource_ImplBase implements ExternalResourceLocator { private static final String DATABASE = "database"; private static final String DATABASE_FILE = DATABASE+".h2.db"; private static final String UBY_PASSWORD = "uby.password"; private static final String UBY_USERNAME = "uby.username"; private static final String UBY_DIALECT = "uby.dialect"; private static final String UBY_DRIVER = "uby.driver"; private static final String UBY_URL = "uby.url"; /** * When using an embedded database, do not set this parameter. */ public static final String PARAM_URL = "url"; @ConfigurationParameter(name = PARAM_URL, mandatory = false) private String url; public static final String PARAM_DRIVER = "driver"; @ConfigurationParameter(name = PARAM_DRIVER, mandatory = false) private String driver; /** * Hibernate dialect name. For convenience and backwards-compatibility with previous Uby * versions the short names {@code mysql} and {@code h2} are supported. Otherwise, this * must be a full Hibernate dialect class name. * * @see DBConfig#setDb_vendor(String) * @see DBConfig#getDb_vendor() */ public static final String PARAM_DIALECT = "dialect"; @ConfigurationParameter(name = PARAM_DIALECT, mandatory = false) private String dialect; public static final String PARAM_USERNAME = "username"; @ConfigurationParameter(name = PARAM_USERNAME, mandatory = false) private String username; public static final String PARAM_PASSWORD = "password"; @ConfigurationParameter(name = PARAM_PASSWORD, mandatory = false) private String password; /** * Load the model from this location instead of locating the model automatically. If * you are NOT using an embedded database, you need to set this parameter to * {@link ResourceObjectProviderBase#NOT_REQUIRED} * like this: UbyResource.PARAM_MODEL_LOCATION, ResourceObjectProviderBase.NOT_REQUIRED * (i.e. in that case it is mandatory to set this parameter) */ public static final String PARAM_MODEL_LOCATION = ComponentParameters.PARAM_MODEL_LOCATION; @ConfigurationParameter(name = PARAM_MODEL_LOCATION, mandatory = false) protected String modelLocation; /** * Use this language instead of the document language to resolve the model. */ public static final String PARAM_LANGUAGE = ComponentParameters.PARAM_LANGUAGE; @ConfigurationParameter(name = PARAM_LANGUAGE, mandatory = false) protected String language; /** * Override the default variant used to locate the model. */ public static final String PARAM_VARIANT = ComponentParameters.PARAM_VARIANT; @ConfigurationParameter(name = PARAM_VARIANT, mandatory = false) protected String variant; private CasConfigurableProviderBase<Uby> modelProvider; @SuppressWarnings("rawtypes") @Override public boolean initialize(ResourceSpecifier aSpecifier, Map aAdditionalParams) throws ResourceInitializationException { if (!super.initialize(aSpecifier, aAdditionalParams)) { return false; } modelProvider = new ModelProviderBase<Uby>() { { setContextObject(UbyResource.this); setDefault(GROUP_ID, "de.tudarmstadt.ukp.uby"); setDefault(ARTIFACT_ID, "${groupId}-model-data-${language}-${variant}"); setDefault(LOCATION, "classpath:/de/tudarmstadt/ukp/uby/data/lib/data-${language}-${variant}.properties"); setDefault(VARIANT, "light"); setOverride(LOCATION, modelLocation); setOverride(LANGUAGE, language); setOverride(VARIANT, variant); } @Override protected Uby produceResource(URL aUrl) throws IOException { Properties props = getAggregatedProperties(); Properties meta = new Properties(getResourceMetaData()); addOverride(meta, UBY_URL, url); addOverride(meta, UBY_DRIVER, driver); addOverride(meta, UBY_DIALECT, dialect); addOverride(meta, UBY_USERNAME, username); addOverride(meta, UBY_PASSWORD, password); // If an embedded database is to be used, extract database to disk if (aUrl != null) { UbyResource.this.getLogger().info("Using embedded database"); File tmpFolder = File.createTempFile("uby", ".db"); FileUtils.forceDelete(tmpFolder); FileUtils.forceMkdir(tmpFolder); tmpFolder.deleteOnExit(); File tmpDbFile = new File(tmpFolder, DATABASE_FILE); tmpDbFile.deleteOnExit(); UbyResource.this.getLogger().info( "Extracting embedded database to [" + tmpDbFile + "]"); InputStream is = null; OutputStream os = null; try { // FIXME should probably just do nothing if database file is not compressed // and if the URL already points to the file system. is = CompressionUtils.getInputStream(aUrl.toString(), aUrl.openStream()); os = new FileOutputStream(tmpDbFile); IOUtils.copyLarge(is, os); } finally { IOUtils.closeQuietly(os); IOUtils.closeQuietly(is); } // Well... we currently only support H2 as embedded DB. If somebody wants to // use a different embedded DB, we'll have to implement something more // generic here. meta.setProperty(UBY_URL, "jdbc:h2:" + tmpFolder.toURI().toURL().toString() + "/" + DATABASE + ";TRACE_LEVEL_FILE=0"); } else { getLogger().info("Connecting to server..."); } getLogger().info("uby.url: " + meta.getProperty(UBY_URL)); getLogger().info("uby.driver: " + meta.getProperty(UBY_DRIVER)); getLogger().info("uby.dialect: " + meta.getProperty(UBY_DIALECT)); getLogger().info("uby.username: " + meta.getProperty(UBY_USERNAME)); getLogger().info("uby.password: " + (StringUtils.isNotEmpty( meta.getProperty(UBY_PASSWORD)) ? "<set>" : "<unset>")); DBConfig dbConfig = new DBConfig(meta.getProperty(UBY_URL), meta.getProperty(UBY_DRIVER), meta.getProperty(UBY_DIALECT), meta.getProperty(UBY_USERNAME), meta.getProperty(UBY_PASSWORD), false); try { return new Uby(dbConfig); } catch (IllegalArgumentException e) { throw new IOException(e); } } }; return true; } @Override public Uby getResource() { try { modelProvider.configure(); return modelProvider.getResource(); } catch (IOException e) { throw new IllegalStateException(e); } } private static void addOverride(Properties aProps, String aKey, String aValue) { if (aValue != null) { aProps.setProperty(aKey, aValue); } } }