/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2005-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2010-2012, Geomatys
*
* 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;
* version 2.1 of the License.
*
* 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.
*/
package org.geotoolkit.openoffice;
import java.io.File;
import java.io.IOException;
import java.io.FilenameFilter;
import java.io.FileOutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.jar.Pack200;
import java.util.jar.JarOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.LogRecord;
import com.sun.star.lang.XSingleServiceFactory;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.comp.loader.FactoryHelper;
import com.sun.star.registry.XRegistryKey;
/**
* The registration of all formulas provided in this package.
*
* {@section Implementation note}
* No GeoAPI or Geotk classes should appear in method signature. For example no method should
* contain {@link org.opengis.util.FactoryException} in their {@code throws} declaration. This
* is because those classes can be loaded only after the Pack200 files have been unpacked, which
* is the work of this {@code Registration} class.
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @module
*/
public final class Registration implements FilenameFilter {
/**
* Do not allow instantiation of this class, except for internal use.
*/
private Registration() {
}
/**
* Returns the directory where the add-in is installed.
*
* @return The installation directory.
* @throws URISyntaxException If the path to the add-in JAR file does not have the expected syntax.
*/
private static File getInstallDirectory() throws URISyntaxException {
String path = Registration.class.getResource("Registration.class").toString();
int numParents = 4; // Number of calls to File.getParentFile() needed for reaching the root.
if (path.startsWith("jar:")) {
path = path.substring(4, path.indexOf('!'));
numParents = 1; // The file should be the geotk-openoffice.jar file in the root.
}
File file = new File(new URI(path));
while (--numParents >= 0) {
file = file.getParentFile();
}
return file;
}
/**
* Ensures that the {@code geotk.pack} files have been uncompressed.
*
* @throws URISyntaxException If the path to the add-in JAR file does not have the expected syntax.
* @throws IOException If an error occurred while uncompressing the PACK200 file.
*/
private static void ensureInstalled() throws URISyntaxException, IOException {
final File directory = getInstallDirectory();
final String[] content = directory.list(new Registration());
if (content != null && content.length != 0) {
final Pack200.Unpacker unpacker = Pack200.newUnpacker();
for (final String filename : content) {
final File packFile = new File(directory, filename);
final File jarFile = new File(directory, filename.substring(0, filename.length()-4) + "jar");
try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jarFile))) {
unpacker.unpack(packFile, out);
}
packFile.delete();
}
/*
* Ensures that the EPSG database is installed. We force the EPSG installation at add-in
* installation time rather than the first time a user ask for a referencing operations,
* because users may be less surprised by a delay at installation time than at use time.
* However if the EPSG database is deleted after the installation, it will be recreated
* when first needed.
*
* Note: do not reach this code before all Pack200 files have been unpacked.
* Remainder: no GeoAPI or Geotk classes in any method signature of this class!
*/
// TODO: to be re-enabled after the migration to SIS.
// try {
// final EpsgInstaller installer = new EpsgInstaller();
// if (!installer.exists()) {
// installer.call();
// }
// } catch (Throwable e) {
// unexpectedException(EpsgInstaller.class, "call", e);
// // Ignore. A new attempt to create the EPSG database will be performed
// // when first needed, and the user may see the error at that time.
// }
}
}
/**
* Logs the given exception.
*/
private static void unexpectedException(final Class<?> classe, final String method, final Throwable exception) {
final Logger logger = Logger.getLogger("org.geotoolkit.openoffice");
final LogRecord record = new LogRecord(Level.WARNING, exception.getLocalizedMessage());
record.setLoggerName(logger.getName());
record.setSourceClassName(classe.getName());
record.setSourceMethodName(method);
record.setThrown(exception);
logger.log(record);
}
/**
* Filters a directory content in order to retain only the {@code "*.pack"} files.
*
* @param directory The add-in installation directory.
* @param name The name of a file in the given directory.
*/
@Override
public boolean accept(final File directory, final String name) {
return name.endsWith(".pack");
}
/**
* Returns a factory for creating the service.
* This method is called by the {@code com.sun.star.comp.loader.JavaLoader}; do not rename!
*
* @param implementation The name of the implementation for which a service is desired.
* @param factories The service manager to be used if needed.
* @param registry The registry key
* @return A factory for creating the component.
* @throws URISyntaxException If the path to the add-in JAR file does not have the expected syntax.
* @throws IOException If an error occurred while uncompressing the PACK200 file.
*/
public static XSingleServiceFactory __getServiceFactory(
final String implementation,
final XMultiServiceFactory factories,
final XRegistryKey registry) throws URISyntaxException, IOException
{
ensureInstalled();
if (implementation.equals(org.geotoolkit.openoffice.geoapi.Referencing.class.getName())) {
return FactoryHelper.getServiceFactory(org.geotoolkit.openoffice.geoapi.Referencing.class,
org.geotoolkit.openoffice.geoapi.Referencing.__serviceName, factories, registry);
}
if (implementation.equals(Referencing.class.getName())) {
return FactoryHelper.getServiceFactory(Referencing.class, Referencing.__serviceName, factories, registry);
}
if (implementation.equals(Nature.class.getName())) {
return FactoryHelper.getServiceFactory(Nature.class, Nature.__serviceName, factories, registry);
}
return null;
}
/**
* Writes the service information into the given registry key.
* This method is called by the {@code com.sun.star.comp.loader.JavaLoader}; do not rename!
*
* @param registry The registry key.
* @return {@code true} if the operation succeeded.
* @throws URISyntaxException If the path to the add-in JAR file does not have the expected syntax.
* @throws IOException If an error occurred while uncompressing the PACK200 file.
*/
public static boolean __writeRegistryServiceInfo(final XRegistryKey registry)
throws URISyntaxException, IOException
{
ensureInstalled();
return register(org.geotoolkit.openoffice.geoapi.Referencing.class,
org.geotoolkit.openoffice.geoapi.Referencing.__serviceName, registry)
&& register(Referencing.class, Referencing.__serviceName, registry)
&& register(Nature .class, Nature. __serviceName, registry);
}
/**
* Helper method for the above {@link #__writeRegistryServiceInfo} method.
*/
private static boolean register(final Class<? extends Formulas> classe,
final String serviceName, final XRegistryKey registry)
{
final String cn = classe.getName();
return FactoryHelper.writeRegistryServiceInfo(cn, serviceName, registry)
&& FactoryHelper.writeRegistryServiceInfo(cn, Formulas.ADDIN_SERVICE, registry);
}
}