bf7ddb5d5625966d05a13566db889c57f3a885e2
[simantics/platform.git] / bundles / org.simantics.excel / src / org / simantics / excel / Excel.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.excel;
13
14 import java.io.File;
15 import java.io.IOException;
16 import java.io.PrintStream;
17 import java.net.URL;
18 import java.net.URLDecoder;
19 import java.nio.charset.Charset;
20 import java.util.ArrayList;
21 import java.util.Enumeration;
22 import java.util.UUID;
23 import java.util.concurrent.Callable;
24 import java.util.concurrent.ExecutionException;
25 import java.util.concurrent.Executors;
26 import java.util.concurrent.Future;
27 import java.util.concurrent.ScheduledExecutorService;
28 import java.util.concurrent.TimeUnit;
29 import java.util.concurrent.TimeoutException;
30
31 import org.eclipse.core.resources.IWorkspace;
32 import org.eclipse.core.resources.IWorkspaceRoot;
33 import org.eclipse.core.resources.ResourcesPlugin;
34 import org.eclipse.core.runtime.FileLocator;
35 import org.eclipse.core.runtime.IPath;
36 import org.eclipse.core.runtime.Path;
37 import org.eclipse.core.runtime.Platform;
38 import org.osgi.framework.Bundle;
39 import org.osgi.framework.BundleContext;
40 import org.simantics.excel.ExecEnvironment.ARCHType;
41 import org.simantics.excel.ExecEnvironment.OSType;
42 import org.simantics.utils.FileUtils;
43
44 public class Excel {
45
46     private static Excel instance;
47
48     public static Excel getInstance(PrintStream out) throws ExcelException {
49
50         if(instance == null) {
51                 if (Platform.inDevelopmentMode()) {
52                 Bundle b = Activator.getDefault().getBundle();
53                 URL url = FileLocator.find(b, new Path(""), null);
54                 try {
55                     extractDir = new File(URLDecoder.decode(FileLocator.toFileURL(url).getPath(), "UTF-8"));
56                 } catch (IOException e) {
57                     e.printStackTrace(out);
58                     throw new ExcelException(e);
59                 }
60             } else {
61                 try {
62                     start(out);
63                 } catch (IOException e) {
64                     e.printStackTrace(out);
65                     throw new ExcelException(e);
66                 } catch (Throwable t) {
67                     t.printStackTrace(out);
68                     throw new ExcelException(t);
69                 }
70             }
71
72                 instance = new Excel(out);
73             
74         }
75
76         return instance;
77
78     }
79
80     public File getDirectory() throws IOException {
81
82         Bundle b = Platform.getBundle(Activator.PLUGIN_ID);
83         if (b == null)
84             throw new AssertionError("Could not resolve bundle '" + Activator.PLUGIN_ID + "' although were running in its fragment. Should not happen.");
85
86         BundleContext context = b.getBundleContext();
87         if (context == null)
88             throw new AssertionError("Could not get bundle context for bundle '" + Activator.PLUGIN_ID + "'. Bundle state is " + b.getState() + ".");
89
90         File extractDir = context.getDataFile("");
91         if (extractDir == null)
92             throw new IOException("Bundle '" + Activator.PLUGIN_ID + " context has no file system support. Cannot extract server executables.");
93
94         if (!extractDir.exists())
95             if (!extractDir.mkdir())
96                 throw new IOException("Could not create directory '" + extractDir.getCanonicalPath() + "' for storing Balas solver data.");
97         
98         return extractDir;
99         
100     }
101     
102     public String getContainer() {
103         return UUID.randomUUID().toString();
104     }
105     
106     public String getFile(String name) {
107         try {
108             return getDirectory().getAbsolutePath() + "\\" + name;
109         } catch (IOException e) {
110             e.printStackTrace();
111             return null;
112         }
113     }
114     
115     private Excel(PrintStream out) throws ExcelException {
116
117         try {
118                 Future<?> future = init_(extractDir + File.separator);
119                         future.get(10, TimeUnit.SECONDS);
120                 } catch (InterruptedException e) {
121                         throw new ExcelException(e);
122                 } catch (ExecutionException e) {
123                         throw new ExcelException(e);
124                 } catch (TimeoutException e) {
125                         throw new ExcelException(e);
126                 }
127
128     }
129
130     public static IPath getAbsolutePath(String inBundle, String fullpath) {
131         Bundle b = Platform.getBundle(inBundle);
132         if (b == null)
133             return null;
134         return getAbsolutePath(b, fullpath);
135     }
136
137     public static IPath getAbsolutePath(Bundle inBundle, String fullpath) {
138 //      System.out.println("getAbsolutePath: " + inBundle + ", " + fullpath);
139         IPath path = new Path(fullpath);
140         URL u = FileLocator.find(inBundle, path, null);
141         if (u != null) {
142             try {
143                 u = FileLocator.resolve(u);
144 //              System.out.println("  PROTOCOL: " + u.getProtocol());
145 //              System.out.println("  FILE: " + u.getFile());
146                 // an absolute path is only available for the file protocol.
147                 if ("file".equals(u.getProtocol())) {
148                     IPath p = new Path(new File(u.getFile()).getAbsolutePath());
149                     return p;
150                 }
151             } catch (Exception e) {
152             }
153         }
154         return null;
155     }
156
157     private static final Charset  ascii             = Charset.forName("US-ASCII");
158
159     private static final String   REQUIRED_FILES_DESCRIPTOR_FILE = "required_files.txt";
160
161     /**
162      * List here all the files that are required from this bundle to be able to
163      * run the ProCoreServer executable. This is necessary for the starter core
164      * below to be able to extract all the needed files incase the bundle
165      * happens to be deployed as a JAR.
166      */
167     private static final String[] DEFAULT_REQUIRED_FILES    = {
168         "SimanticsExcel.dll", "SimanticsExcel_64.dll"
169     };
170
171     /**
172      * The extraction directory is stored as a static field so that it can be
173      * used to check whether the files have already been extracted.
174      */
175     static private  File           extractDir        = null;
176
177     static private String[]              requiredFiles     = null;
178
179     static private boolean               needExtraction    = false;
180
181     private static IPath getAbsolutePath(String fullpath) {
182         Bundle b = Platform.getBundle(Activator.PLUGIN_ID);
183         if (b == null)
184             return null;
185 //      System.out.println("getAbsolutePath: " + inBundle + ", " + fullpath);
186         IPath path = new Path(fullpath);
187         URL u = FileLocator.find(b, path, null);
188         if (u != null) {
189             try {
190                 u = FileLocator.resolve(u);
191 //              System.out.println("  PROTOCOL: " + u.getProtocol());
192 //              System.out.println("  FILE: " + u.getFile());
193                 // an absolute path is only available for the file protocol.
194                 if ("file".equals(u.getProtocol())) {
195                     IPath p = new Path(new File(u.getFile()).getAbsolutePath());
196                     return p;
197                 }
198             } catch (Exception e) {
199             }
200         }
201         return null;
202     }
203
204     static String[] getRequiredFiles() {
205
206         if (requiredFiles != null)
207             return requiredFiles;
208
209         Bundle b = Platform.getBundle(Activator.PLUGIN_ID);
210         if (b == null)
211             return null;
212
213         ArrayList<Enumeration<?>> enu = new ArrayList<Enumeration<?>>();
214
215         enu.add(b.findEntries("/", "*.dll", true));
216         //enu.add(b.findEntries("/", "*.manifest", true));
217
218         ArrayList<String> filez = new ArrayList<String>();
219
220         for(Enumeration<?> e : enu) {
221             while(e.hasMoreElements()) {
222                 URL url = (URL)e.nextElement();
223                 filez.add(url.getFile());
224 //                      System.out.println(url.getFile());
225             }
226         }
227
228         requiredFiles = filez.toArray(new String[filez.size()]);
229
230         return requiredFiles;
231
232     }
233
234     private static File extractFiles() throws IOException {
235         Bundle b = Platform.getBundle(Activator.PLUGIN_ID);
236         if (b == null)
237             throw new AssertionError("Could not resolve bundle '" + Activator.PLUGIN_ID + "' although were running in it. Should not happen.");
238
239         //System.out.println("bundle dir: " + baseDir);
240         for (String file : getRequiredFiles()) {
241             // FileLocator find files in fragments also, Bundle.getEntry won't do that.
242             URL url = FileLocator.find(b, new Path(file), null);
243             File fzz = new File(extractDir, file);
244             Path path = new Path(fzz.getAbsolutePath());
245             path.removeLastSegments(1).toFile().mkdirs();
246             FileUtils.copyResource(url, fzz, false);
247         }
248         return extractDir;
249     }
250
251     public static final String EXCEL_FOLDER = "Excel"; //$NON-NLS-1$
252     
253     public static void start(PrintStream out) throws IOException {
254
255         Bundle b = Platform.getBundle(Activator.PLUGIN_ID);
256         if (b == null)
257             throw new AssertionError("Could not resolve bundle '" + Activator.PLUGIN_ID + "' although were running in its fragment. Should not happen.");
258
259         BundleContext context = b.getBundleContext();
260         if (context == null)
261             throw new AssertionError("Could not get bundle context for bundle '" + Activator.PLUGIN_ID + "'. Bundle state is " + b.getState() + ".");
262
263         IWorkspace workspace = ResourcesPlugin.getWorkspace();
264         IWorkspaceRoot workspaceRoot = workspace.getRoot();
265         extractDir = new File(workspaceRoot.getLocation().toFile(), EXCEL_FOLDER);
266         
267         if (!extractDir.exists())
268             if (!extractDir.mkdir())
269                 throw new IOException("Could not create directory '" + extractDir.getCanonicalPath() + "' for storing Balas solver data.");
270
271         String asd = "";
272         ExecEnvironment env = ExecEnvironment.calculate();
273         if (env.os == OSType.WINDOWS) {
274             if (env.arch == ARCHType.X86) {
275                 asd = extractDir + "\\SimanticsExcel.dll";
276             } else if (env.arch == ARCHType.X86_64) {
277                 asd = extractDir + "\\SimanticsExcel_64.dll";
278             }
279         }
280
281         
282         File test = new File(asd);
283         if(test.exists()) {
284             needExtraction = false;
285             return;
286         } else {
287             needExtraction = true;
288         }
289
290         // Resolve executable location
291         if (needExtraction) {
292             extractDir = extractFiles();
293         } else {
294             out.println("needExtraction=false");
295         }
296
297     }
298
299     // Initialization
300     private native int init();
301     private native String open(String fileName, String sheetName);
302     private native String getModifications(int handle);
303     private native int setDouble(int handle, int row, int column, double value);
304     private native int setString(int handle, int row, int column, String value);
305     private native int setName(int handle, int row, int column, String value);
306     private native int setVisible(int handle, boolean value);
307     private native int close(int handle);
308     
309 //    private native double getDouble(int handle, int row, int column);
310 //    private native String getString(int handle, int row, int column);
311
312     final ScheduledExecutorService  scheduler = Executors.newSingleThreadScheduledExecutor();
313
314     public Future<?> init_(final String path) {
315         return scheduler.submit(new Runnable() {
316                 @Override
317                 public void run() {
318
319                     String asd = "";
320                 ExecEnvironment env = ExecEnvironment.calculate();
321                 if (env.os == OSType.WINDOWS) {
322                     if (env.arch == ARCHType.X86) {
323                         asd = extractDir + "\\SimanticsExcel.dll";
324                     } else if (env.arch == ARCHType.X86_64) {
325                         asd = extractDir + "\\SimanticsExcel_64.dll";
326                     }
327                 }
328                 System.load(asd);
329                 init();
330                 }
331         });
332     }
333
334     public String open_(final String fileName, final String sheetName) {
335         try {
336             return scheduler.submit(new Callable<String>() {
337                 @Override
338                 public String call() throws Exception {
339                     return open(fileName, sheetName);
340                 }
341             }).get();
342         } catch (Exception e) {
343             e.printStackTrace();
344             return "";
345         }
346     }
347
348     public int setDouble_(final int handle, final int row, final int column, final double value) {
349         try {
350             return scheduler.submit(new Callable<Integer>() {
351                 @Override
352                 public Integer call() throws Exception {
353 //                    System.out.println("Excel: setDouble at " + row + "-" + column); 
354                     return setDouble(handle, row, column, value);
355                 }
356             }).get();
357         } catch (Exception e) {
358             e.printStackTrace();
359             return -1;
360         }
361     }
362
363     public int setString_(final int handle, final int row, final int column, final String value) {
364         try {
365             return scheduler.submit(new Callable<Integer>() {
366                 @Override
367                 public Integer call() throws Exception {
368 //                    System.out.println("Excel: setString at " + row + "-" + column); 
369                     return setString(handle, row, column, value);
370                 }
371             }).get();
372         } catch (Exception e) {
373             e.printStackTrace();
374             return -1;
375         }
376     }
377
378     public String getModifications_(final int handle) {
379         try {
380             return scheduler.submit(new Callable<String>() {
381                 @Override
382                 public String call() throws Exception {
383 //                    System.out.println("Excel: setString at " + row + "-" + column); 
384                     return getModifications(handle);
385                 }
386             }).get();
387         } catch (Exception e) {
388             e.printStackTrace();
389             return "";
390         }
391     }
392
393     public int setName_(final int handle, final int row, final int column, final String value) {
394         try {
395             return scheduler.submit(new Callable<Integer>() {
396                 @Override
397                 public Integer call() throws Exception {
398 //                    System.out.println("Excel: setString at " + row + "-" + column); 
399                     return setName(handle, row, column, value);
400                 }
401             }).get();
402         } catch (Exception e) {
403             e.printStackTrace();
404             return -1;
405         }
406     }
407
408     public int setVisible_(final int handle, final Boolean value) {
409         try {
410             return scheduler.submit(new Callable<Integer>() {
411                 @Override
412                 public Integer call() throws Exception {
413 //                    System.out.println("Excel: setString at " + row + "-" + column); 
414                     return setVisible(handle, value);
415                 }
416             }).get();
417         } catch (Exception e) {
418             e.printStackTrace();
419             return -1;
420         }
421     }
422
423     public int close_(final int handle) {
424         try {
425             return scheduler.submit(new Callable<Integer>() {
426                 @Override
427                 public Integer call() throws Exception {
428 //                    System.out.println("Excel: close " + handle);
429                     int ret = close(handle); 
430 //                    System.out.println("Excel: close = " + ret);
431                     return ret;
432                 }
433             }).get();
434         } catch (Exception e) {
435             e.printStackTrace();
436             return -1;
437         }
438     }
439     
440 //    public double getDouble_(final int handle, final int row, final int column) {
441 //        try {
442 //            return scheduler.submit(new Callable<Double>() {
443 //                @Override
444 //                public Double call() throws Exception {
445 //                    return getDouble(handle, row, column);
446 //                }
447 //            }).get();
448 //        } catch (Exception e) {
449 //            e.printStackTrace();
450 //            return Double.NaN;
451 //        }
452 //    }
453 //    
454 //    public String getString_(final int handle, final int row, final int column) {
455 //        try {
456 //            return scheduler.submit(new Callable<String>() {
457 //                @Override
458 //                public String call() throws Exception {
459 //                    return getString(handle, row, column);
460 //                }
461 //            }).get();
462 //        } catch (Exception e) {
463 //            e.printStackTrace();
464 //            return null;
465 //        }
466 //    }
467
468 }