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