1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in Industry THTH ry.
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.db.procore.server.environment.windows;
\r
14 import java.io.Closeable;
\r
15 import java.io.File;
\r
16 import java.io.FileInputStream;
\r
17 import java.io.FileNotFoundException;
\r
18 import java.io.FileOutputStream;
\r
19 import java.io.IOException;
\r
20 import java.io.InputStream;
\r
21 import java.net.URL;
\r
22 import java.net.URLDecoder;
\r
23 import java.security.MessageDigest;
\r
24 import java.security.NoSuchAlgorithmException;
\r
25 import java.util.Arrays;
\r
27 import org.simantics.db.procore.server.environment.ExecutionEnvironment;
\r
28 import org.simantics.db.procore.server.environment.ExecutionEnvironmentException;
\r
31 * Provides Java access to Windows Msi API functions:
\r
33 * <li>{@link #MsiQueryProductState(String)} (see <a
\r
34 * href="http://msdn.microsoft.com/en-us/library/aa370363(VS.85).aspx">MSDN</a>)</li>
\r
37 * @author Tuukka Lehtonen
\r
41 public static void checkOneOfProductsInstalled(Product... products) throws ExecutionEnvironmentException {
\r
42 StringBuilder sb = new StringBuilder();
\r
43 sb.append("None of the following products are installed properly:\n");
\r
44 for (Product product : products) {
\r
45 ProductState state = Msi.MsiQueryProductState(product.getCode());
\r
48 // One of the listed products is installed OK.
\r
51 sb.append("\t" + product);
\r
52 sb.append(" - MsiQueryProductState returned ");
\r
57 throw new ExecutionEnvironmentException("Cannot run ProCore database server in this environment due to the following problems:\n" + sb.toString(), Arrays.asList(products));
\r
60 public static void checkProductsInstalled(Product... products) throws ExecutionEnvironmentException {
\r
61 StringBuilder sb = new StringBuilder();
\r
62 for (Product product : products) {
\r
63 ProductState state = Msi.MsiQueryProductState(product.getCode());
\r
69 sb.append("\tProduct " + product + " is not installed properly, MsiQueryProductState returned " + state);
\r
73 if (sb.length() > 0) {
\r
74 // Something is not installed right, throw exception
\r
75 throw new ExecutionEnvironmentException("Cannot run ProCore database server in this environment due to the following problems:\n" + sb.toString(), Arrays.asList(products));
\r
79 // -------------------------------------------------------------------------
\r
81 public static ProductState MsiQueryProductState(String productCode) {
\r
82 int result = MsiQueryProductState0(productCode);
\r
83 return ProductState.of(result);
\r
86 private static native int MsiQueryProductState0(String productCode);
\r
88 // -------------------------------------------------------------------------
\r
90 private static final String DLL_NAME = "msijni.dll";
\r
91 private static final String DLL_NAME_64 = "msijni64.dll";
\r
97 private static void initialize() {
\r
98 ExecutionEnvironment env = ExecutionEnvironment.calculate();
\r
99 String libName = null;
\r
100 switch (env.arch) {
\r
102 libName = DLL_NAME;
\r
105 libName = DLL_NAME_64;
\r
111 URL libURL = Msi.class.getResource("/" + libName);
\r
112 if (libURL != null) {
\r
114 if ("file".equals(libURL.getProtocol())) {
\r
115 File path = new File(URLDecoder.decode(libURL.getPath(), "UTF-8"));
\r
118 File libFile = extractLib(libURL, libName);
\r
119 initialize(libFile);
\r
121 } catch (IOException e) {
\r
122 e.printStackTrace();
\r
127 private static void initialize(File path) {
\r
128 //System.out.println("load msijni: " + path);
\r
129 System.load(path.toString());
\r
133 * Extracts the specified source file in the specified bundle into the
\r
134 * specified local directory.
\r
136 * @param url the source URL to stream the resource from
\r
137 * @param targetFile the target file to write the resource to
\r
138 * @param deleteOnExit <code>true</code> to use {@link File#deleteOnExit()}
\r
139 * on the resulting file. Note that this does not guarantee that the
\r
140 * file is deleted when the JVM exits
\r
141 * @return the resulting file
\r
142 * @throws FileNotFoundException
\r
144 private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {
\r
145 FileOutputStream os = null;
\r
146 InputStream is = null;
\r
148 if (targetFile.exists())
\r
149 targetFile.delete();
\r
151 is = url.openStream();
\r
153 byte [] buffer = new byte [16384];
\r
154 os = new FileOutputStream (targetFile);
\r
155 while ((read = is.read (buffer)) != -1) {
\r
156 os.write(buffer, 0, read);
\r
163 uncheckedClose(os);
\r
164 uncheckedClose(is);
\r
169 private static void uncheckedClose(Closeable closeable) {
\r
171 if (closeable != null)
\r
173 } catch (IOException e) {
\r
178 private static File extractLib(URL libURL, String libName) throws FileNotFoundException, IOException {
\r
179 String tmpDirStr = System.getProperty("java.io.tmpdir");
\r
180 if (tmpDirStr == null)
\r
181 throw new NullPointerException("java.io.tmpdir property is null");
\r
182 File tmpDir = new File(tmpDirStr);
\r
183 File libFile = new File(tmpDir, libName);
\r
185 if (libFile.exists()) {
\r
186 if (libFile.isFile()) {
\r
188 byte[] origSum = computeSum(libURL);
\r
189 byte[] targetSum = computeSum(libFile);
\r
190 if (Arrays.equals(origSum, targetSum))
\r
192 } catch (NoSuchAlgorithmException e) {
\r
193 // TODO Auto-generated catch block
\r
194 e.printStackTrace();
\r
199 return copyResource(libURL, libFile);
\r
202 public static byte[] computeSum(InputStream in) throws IOException {
\r
204 throw new IllegalArgumentException("Input cannot be null!");
\r
207 MessageDigest md = MessageDigest.getInstance("MD5");
\r
208 byte[] data = new byte[64 * 1024];
\r
211 int read = in.read(data);
\r
213 return md.digest();
\r
215 md.update(data, 0, read);
\r
217 } catch (NoSuchAlgorithmException e) {
\r
218 // Should not be possible for MD5
\r
219 throw new IOException(e);
\r
223 public static byte[] computeSum(File f) throws IOException, NoSuchAlgorithmException {
\r
224 InputStream in = null;
\r
226 in = new FileInputStream(f);
\r
227 return computeSum(in);
\r
234 public static byte[] computeSum(URL url) throws IOException, NoSuchAlgorithmException {
\r
235 InputStream in = null;
\r
237 in = url.openStream();
\r
238 return computeSum(in);
\r