/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.db.procore.server.environment.windows; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLDecoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.simantics.db.procore.server.environment.ExecutionEnvironment; import org.simantics.db.procore.server.environment.ExecutionEnvironmentException; /** * Provides Java access to Windows Msi API functions: * * * @author Tuukka Lehtonen */ public class Msi { public static void checkOneOfProductsInstalled(Product... products) throws ExecutionEnvironmentException { StringBuilder sb = new StringBuilder(); sb.append("None of the following products are installed properly:\n"); for (Product product : products) { ProductState state = Msi.MsiQueryProductState(product.getCode()); switch (state) { case DEFAULT: // One of the listed products is installed OK. return; default: sb.append("\t" + product); sb.append(" - MsiQueryProductState returned "); sb.append(state); sb.append("\n"); } } throw new ExecutionEnvironmentException("Cannot run ProCore database server in this environment due to the following problems:\n" + sb.toString(), Arrays.asList(products)); } public static void checkProductsInstalled(Product... products) throws ExecutionEnvironmentException { StringBuilder sb = new StringBuilder(); for (Product product : products) { ProductState state = Msi.MsiQueryProductState(product.getCode()); switch (state) { case DEFAULT: // Installed OK continue; default: sb.append("\tProduct " + product + " is not installed properly, MsiQueryProductState returned " + state); sb.append("\n"); } } if (sb.length() > 0) { // Something is not installed right, throw exception throw new ExecutionEnvironmentException("Cannot run ProCore database server in this environment due to the following problems:\n" + sb.toString(), Arrays.asList(products)); } } // ------------------------------------------------------------------------- public static ProductState MsiQueryProductState(String productCode) { int result = MsiQueryProductState0(productCode); return ProductState.of(result); } private static native int MsiQueryProductState0(String productCode); // ------------------------------------------------------------------------- private static final String DLL_NAME = "msijni.dll"; private static final String DLL_NAME_64 = "msijni64.dll"; static { initialize(); } private static void initialize() { ExecutionEnvironment env = ExecutionEnvironment.calculate(); String libName = null; switch (env.arch) { case X86: libName = DLL_NAME; break; case X86_64: libName = DLL_NAME_64; break; default: return; } URL libURL = Msi.class.getResource("/" + libName); if (libURL != null) { try { if ("file".equals(libURL.getProtocol())) { File path = new File(URLDecoder.decode(libURL.getPath(), "UTF-8")); initialize(path); } else { File libFile = extractLib(libURL, libName); initialize(libFile); } } catch (IOException e) { e.printStackTrace(); } } } private static void initialize(File path) { //System.out.println("load msijni: " + path); System.load(path.toString()); } /** * Extracts the specified source file in the specified bundle into the * specified local directory. * * @param url the source URL to stream the resource from * @param targetFile the target file to write the resource to * @param deleteOnExit true to use {@link File#deleteOnExit()} * on the resulting file. Note that this does not guarantee that the * file is deleted when the JVM exits * @return the resulting file * @throws FileNotFoundException */ private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException { FileOutputStream os = null; InputStream is = null; try { if (targetFile.exists()) targetFile.delete(); is = url.openStream(); int read; byte [] buffer = new byte [16384]; os = new FileOutputStream (targetFile); while ((read = is.read (buffer)) != -1) { os.write(buffer, 0, read); } os.close (); is.close (); return targetFile; } finally { uncheckedClose(os); uncheckedClose(is); } } private static void uncheckedClose(Closeable closeable) { try { if (closeable != null) closeable.close(); } catch (IOException e) { //ignore } } private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException { String tmpDirStr = System.getProperty("java.io.tmpdir"); if (tmpDirStr == null) throw new NullPointerException("java.io.tmpdir property is null"); File tmpDir = new File(tmpDirStr); File libFile = new File(tmpDir, libName); if (libFile.exists()) { if (libFile.isFile()) { try { byte[] origSum = computeSum(libURL); byte[] targetSum = computeSum(libFile); if (Arrays.equals(origSum, targetSum)) return libFile; } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return copyResource(libURL, libFile); } public static byte[] computeSum(InputStream in) throws IOException { if (in == null) throw new IllegalArgumentException("Input cannot be null!"); try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] data = new byte[64 * 1024]; while (true) { int read = in.read(data); if (read == -1) { return md.digest(); } md.update(data, 0, read); } } catch (NoSuchAlgorithmException e) { // Should not be possible for MD5 throw new IOException(e); } } public static byte[] computeSum(File f) throws IOException, NoSuchAlgorithmException { InputStream in = null; try { in = new FileInputStream(f); return computeSum(in); } finally { if (in != null) in.close(); } } public static byte[] computeSum(URL url) throws IOException, NoSuchAlgorithmException { InputStream in = null; try { in = url.openStream(); return computeSum(in); } finally { if (in != null) in.close(); } } }