]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.db.procore.server.environment/src/org/simantics/db/procore/server/environment/windows/Msi.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.db.procore.server.environment / src / org / simantics / db / procore / server / environment / windows / Msi.java
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
8  *\r
9  * Contributors:\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
13 \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
26 \r
27 import org.simantics.db.procore.server.environment.ExecutionEnvironment;\r
28 import org.simantics.db.procore.server.environment.ExecutionEnvironmentException;\r
29 \r
30 /**\r
31  * Provides Java access to Windows Msi API functions:\r
32  * <ul>\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
35  * </ul>\r
36  * \r
37  * @author Tuukka Lehtonen\r
38  */\r
39 public class Msi {\r
40 \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
46             switch (state) {\r
47                 case DEFAULT:\r
48                     // One of the listed products is installed OK.\r
49                     return;\r
50                 default:\r
51                     sb.append("\t" + product);\r
52                     sb.append(" - MsiQueryProductState returned ");\r
53                     sb.append(state);\r
54                     sb.append("\n");\r
55             }\r
56         }\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
58     }\r
59 \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
64             switch (state) {\r
65                 case DEFAULT:\r
66                     // Installed OK\r
67                     continue;\r
68                 default:\r
69                     sb.append("\tProduct " + product + " is not installed properly, MsiQueryProductState returned " + state);\r
70                     sb.append("\n");\r
71             }\r
72         }\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
76         }\r
77     }\r
78 \r
79     // -------------------------------------------------------------------------\r
80 \r
81     public static ProductState MsiQueryProductState(String productCode) {\r
82         int result = MsiQueryProductState0(productCode);\r
83         return ProductState.of(result);\r
84     }\r
85 \r
86     private static native int MsiQueryProductState0(String productCode);\r
87 \r
88     // -------------------------------------------------------------------------\r
89 \r
90     private static final String DLL_NAME = "msijni.dll";\r
91     private static final String DLL_NAME_64 = "msijni64.dll";\r
92 \r
93     static {\r
94         initialize();\r
95     }\r
96 \r
97     private static void initialize() {\r
98         ExecutionEnvironment env = ExecutionEnvironment.calculate();\r
99         String libName = null;\r
100         switch (env.arch) {\r
101             case X86:\r
102                 libName = DLL_NAME;\r
103                 break;\r
104             case X86_64:\r
105                 libName = DLL_NAME_64;\r
106                 break;\r
107             default:\r
108                 return;\r
109         }\r
110 \r
111         URL libURL = Msi.class.getResource("/" + libName);\r
112         if (libURL != null) {\r
113             try {\r
114                 if ("file".equals(libURL.getProtocol())) {\r
115                     File path = new File(URLDecoder.decode(libURL.getPath(), "UTF-8"));\r
116                     initialize(path);\r
117                 } else {\r
118                     File libFile = extractLib(libURL, libName);\r
119                     initialize(libFile);\r
120                 }\r
121             } catch (IOException e) {\r
122                 e.printStackTrace();\r
123             }\r
124         }\r
125     }\r
126 \r
127     private static void initialize(File path) {\r
128         //System.out.println("load msijni: " + path);\r
129         System.load(path.toString());\r
130     }\r
131 \r
132     /**\r
133      * Extracts the specified source file in the specified bundle into the\r
134      * specified local directory.\r
135      * \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
143      */\r
144     private static File copyResource(URL url, File targetFile) throws IOException, FileNotFoundException {\r
145         FileOutputStream os = null;\r
146         InputStream is = null;\r
147         try {\r
148             if (targetFile.exists())\r
149                 targetFile.delete();\r
150 \r
151             is = url.openStream();\r
152             int read;\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
157             }\r
158             os.close ();\r
159             is.close ();\r
160 \r
161             return targetFile;\r
162         } finally {\r
163             uncheckedClose(os);\r
164             uncheckedClose(is);\r
165         }\r
166     }\r
167 \r
168 \r
169     private static void uncheckedClose(Closeable closeable) {\r
170         try {\r
171             if (closeable != null)\r
172                 closeable.close();\r
173         } catch (IOException e) {\r
174             //ignore\r
175         }\r
176     }\r
177 \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
184 \r
185         if (libFile.exists()) {\r
186             if (libFile.isFile()) {\r
187                 try {\r
188                     byte[] origSum = computeSum(libURL);\r
189                     byte[] targetSum = computeSum(libFile);\r
190                     if (Arrays.equals(origSum, targetSum))\r
191                         return libFile;\r
192                 } catch (NoSuchAlgorithmException e) {\r
193                     // TODO Auto-generated catch block\r
194                     e.printStackTrace();\r
195                 }\r
196             }\r
197         }\r
198 \r
199         return copyResource(libURL, libFile);\r
200     }\r
201 \r
202     public static byte[] computeSum(InputStream in) throws IOException {\r
203         if (in == null)\r
204             throw new IllegalArgumentException("Input cannot be null!");\r
205 \r
206         try {\r
207             MessageDigest md = MessageDigest.getInstance("MD5");\r
208             byte[] data = new byte[64 * 1024];\r
209 \r
210             while (true) {\r
211                 int read = in.read(data);\r
212                 if (read == -1) {\r
213                     return md.digest();\r
214                 }\r
215                 md.update(data, 0, read);\r
216             }\r
217         } catch (NoSuchAlgorithmException e) {\r
218             // Should not be possible for MD5\r
219             throw new IOException(e);\r
220         }\r
221     }\r
222 \r
223     public static byte[] computeSum(File f) throws IOException, NoSuchAlgorithmException {\r
224         InputStream in = null;\r
225         try {\r
226             in = new FileInputStream(f);\r
227             return computeSum(in);\r
228         } finally {\r
229             if (in != null)\r
230                 in.close();\r
231         }\r
232     }\r
233 \r
234     public static byte[] computeSum(URL url) throws IOException, NoSuchAlgorithmException {\r
235         InputStream in = null;\r
236         try {\r
237             in = url.openStream();\r
238             return computeSum(in);\r
239         } finally {\r
240             if (in != null)\r
241                 in.close();\r
242         }\r
243     }\r
244 \r
245 }