This project has retired. For details please refer to its Attic page.
ClientHelper xref

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.workbench;
20  
21  import groovy.lang.Binding;
22  import groovy.ui.Console;
23  import groovy.util.GroovyScriptEngine;
24  
25  import java.awt.Color;
26  import java.awt.Component;
27  import java.awt.Cursor;
28  import java.awt.Desktop;
29  import java.awt.Desktop.Action;
30  import java.awt.Toolkit;
31  import java.awt.Window;
32  import java.awt.datatransfer.Clipboard;
33  import java.awt.datatransfer.StringSelection;
34  import java.awt.datatransfer.Transferable;
35  import java.awt.event.ActionEvent;
36  import java.awt.event.ActionListener;
37  import java.io.BufferedOutputStream;
38  import java.io.BufferedReader;
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.FileOutputStream;
42  import java.io.FileReader;
43  import java.io.IOException;
44  import java.io.InputStream;
45  import java.io.InputStreamReader;
46  import java.io.OutputStream;
47  import java.io.PrintWriter;
48  import java.io.Writer;
49  import java.net.URI;
50  import java.net.URL;
51  import java.text.SimpleDateFormat;
52  import java.util.ArrayList;
53  import java.util.Collection;
54  import java.util.Collections;
55  import java.util.GregorianCalendar;
56  import java.util.List;
57  import java.util.Properties;
58  
59  import javax.script.ScriptEngine;
60  import javax.script.ScriptEngineManager;
61  import javax.swing.AbstractAction;
62  import javax.swing.ImageIcon;
63  import javax.swing.InputMap;
64  import javax.swing.JComponent;
65  import javax.swing.JFileChooser;
66  import javax.swing.JMenu;
67  import javax.swing.JMenuItem;
68  import javax.swing.JOptionPane;
69  import javax.swing.JRootPane;
70  import javax.swing.JTable;
71  import javax.swing.KeyStroke;
72  import javax.swing.UIManager;
73  import javax.swing.text.DefaultEditorKit;
74  
75  import org.apache.chemistry.opencmis.client.api.CmisObject;
76  import org.apache.chemistry.opencmis.client.api.Document;
77  import org.apache.chemistry.opencmis.client.api.ObjectId;
78  import org.apache.chemistry.opencmis.client.api.Rendition;
79  import org.apache.chemistry.opencmis.commons.data.ContentStream;
80  import org.apache.chemistry.opencmis.commons.exceptions.CmisBaseException;
81  import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
82  import org.apache.chemistry.opencmis.commons.impl.MimeTypes;
83  import org.apache.chemistry.opencmis.workbench.model.ClientModel;
84  import org.apache.commons.logging.Log;
85  import org.apache.commons.logging.LogFactory;
86  
87  public class ClientHelper {
88  
89      public static final Color LINK_COLOR = new Color(105, 29, 21);
90      public static final Color LINK_SELECTED_COLOR = new Color(255, 255, 255);
91  
92      private static final Log log = LogFactory.getLog(ClientHelper.class);
93      private static final int BUFFER_SIZE = 64 * 1024;
94  
95      private ClientHelper() {
96      }
97  
98      public static void showError(Component parent, Exception ex) {
99          if (log.isErrorEnabled()) {
100             log.error(ex.getClass().getSimpleName() + ": " + ex.getMessage(), ex);
101 
102             if (ex instanceof CmisBaseException) {
103                 CmisBaseException cex = (CmisBaseException) ex;
104 
105                 if (cex.getCode() != null) {
106                     log.error("Error code: " + cex.getCode());
107                 }
108 
109                 if (cex.getErrorContent() != null) {
110                     log.error("Error content: " + cex.getErrorContent());
111                 }
112             }
113         }
114 
115         String exceptionName = ex.getClass().getSimpleName();
116         if (ex instanceof CmisBaseException) {
117             exceptionName = ((CmisBaseException) ex).getExceptionName();
118         }
119 
120         StringBuilder sb = new StringBuilder(ex.getMessage());
121 
122         int width = 80;
123         while (sb.length() > width) {
124             int p = width;
125 
126             int x = sb.indexOf(" ", p);
127             if (x < 0 || x > p + 10) {
128                 x = sb.indexOf("/", p);
129             }
130             if (x < 0 || x > p + 10) {
131                 x = sb.indexOf(":", p);
132             }
133             if (x < 0 || x > p + 10) {
134                 x = p;
135             }
136 
137             sb.insert(x, '\n');
138             width = x + 80;
139         }
140 
141         JOptionPane.showMessageDialog(parent, exceptionName + ":\n" + sb, "Error", JOptionPane.ERROR_MESSAGE);
142     }
143 
144     public static boolean isMacOSX() {
145         return System.getProperty("os.name").startsWith("Mac OS X");
146     }
147 
148     public static void installKeyBindings() {
149         if (isMacOSX()) {
150             final KeyStroke copyKeyStroke = KeyStroke.getKeyStroke("meta pressed C");
151             final KeyStroke pasteKeyStroke = KeyStroke.getKeyStroke("meta pressed V");
152             final KeyStroke cutKeyStroke = KeyStroke.getKeyStroke("meta pressed X");
153             final KeyStroke allKeyStroke = KeyStroke.getKeyStroke("meta pressed A");
154 
155             InputMap textFieldMap = (InputMap) UIManager.get("TextField.focusInputMap");
156             textFieldMap.put(copyKeyStroke, DefaultEditorKit.copyAction);
157             textFieldMap.put(pasteKeyStroke, DefaultEditorKit.pasteAction);
158             textFieldMap.put(cutKeyStroke, DefaultEditorKit.cutAction);
159             textFieldMap.put(allKeyStroke, DefaultEditorKit.selectAllAction);
160 
161             InputMap formattedTextFieldMap = (InputMap) UIManager.get("FormattedTextField.focusInputMap");
162             formattedTextFieldMap.put(copyKeyStroke, DefaultEditorKit.copyAction);
163             formattedTextFieldMap.put(pasteKeyStroke, DefaultEditorKit.pasteAction);
164             formattedTextFieldMap.put(cutKeyStroke, DefaultEditorKit.cutAction);
165             formattedTextFieldMap.put(allKeyStroke, DefaultEditorKit.selectAllAction);
166 
167             InputMap textAreaMap = (InputMap) UIManager.get("TextArea.focusInputMap");
168             textAreaMap.put(copyKeyStroke, DefaultEditorKit.copyAction);
169             textAreaMap.put(pasteKeyStroke, DefaultEditorKit.pasteAction);
170             textAreaMap.put(cutKeyStroke, DefaultEditorKit.cutAction);
171             textAreaMap.put(allKeyStroke, DefaultEditorKit.selectAllAction);
172 
173             InputMap passwordFieldMap = (InputMap) UIManager.get("PasswordField.focusInputMap");
174             passwordFieldMap.put(pasteKeyStroke, DefaultEditorKit.pasteAction);
175         }
176     }
177 
178     public static void installEscapeBinding(final Window window, final JRootPane rootPane, final boolean dispose) {
179         final KeyStroke stroke = KeyStroke.getKeyStroke("ESCAPE");
180         final InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
181         inputMap.put(stroke, "ESCAPE");
182         rootPane.getActionMap().put("ESCAPE", new AbstractAction() {
183             private static final long serialVersionUID = 1L;
184 
185             @Override
186             public void actionPerformed(ActionEvent e) {
187                 if (dispose) {
188                     window.dispose();
189                 } else {
190                     window.setVisible(false);
191                 }
192             }
193         });
194     }
195 
196     public static ImageIcon getIcon(String name) {
197         URL imageURL = ClientHelper.class.getResource("/images/" + name);
198         if (imageURL != null) {
199             return new ImageIcon(imageURL);
200         }
201 
202         return null;
203     }
204 
205     public static String getDateString(GregorianCalendar cal) {
206         if (cal == null) {
207             return "";
208         }
209 
210         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZ");
211         return sdf.format(cal.getTime());
212     }
213 
214     public static void download(Component component, CmisObject object, String streamId) {
215         ContentStream content = getContentStream(object, streamId);
216         if (content == null) {
217             return;
218         }
219 
220         String filename = content.getFileName();
221         if (filename == null) {
222             if (object instanceof Document) {
223                 filename = ((Document) object).getContentStreamFileName();
224             } else {
225                 filename = object.getName();
226             }
227         }
228 
229         JFileChooser fileChooser = new JFileChooser();
230         fileChooser.setSelectedFile(new File(filename));
231 
232         int chooseResult = fileChooser.showDialog(component, "Download");
233         if (chooseResult == JFileChooser.APPROVE_OPTION) {
234             try {
235                 storeStream(content.getStream(), fileChooser.getSelectedFile());
236             } catch (Exception e) {
237                 showError(component, e);
238             }
239         }
240     }
241 
242     public static void copy(Component component, File file) {
243         JFileChooser fileChooser = new JFileChooser();
244         fileChooser.setSelectedFile(new File(file.getName()));
245 
246         int chooseResult = fileChooser.showDialog(component, "Download");
247         if (chooseResult == JFileChooser.APPROVE_OPTION) {
248             try {
249                 storeStream(new FileInputStream(file), fileChooser.getSelectedFile());
250             } catch (Exception e) {
251                 showError(component, e);
252             }
253         }
254     }
255 
256     public static void open(Component component, CmisObject object, String streamId) {
257         if (!Desktop.isDesktopSupported()) {
258             download(component, object, streamId);
259             return;
260         }
261 
262         Desktop desktop = Desktop.getDesktop();
263 
264         if (!desktop.isSupported(Desktop.Action.OPEN)) {
265             download(component, object, streamId);
266             return;
267         }
268 
269         File file = null;
270 
271         try {
272             file = createTempFileFromDocument(object, streamId);
273         } catch (Exception e) {
274             showError(component, e);
275             return;
276         }
277 
278         try {
279             desktop.open(file);
280         } catch (Exception e) {
281             if (e instanceof IOException) {
282                 copy(component, file);
283             } else {
284                 showError(component, e);
285             }
286         }
287     }
288 
289     public static File createTempFile(String filename) {
290         String tempDir = System.getProperty("java.io.tmpdir");
291         File clientTempDir = new File(tempDir, "cmisworkbench");
292         if (!clientTempDir.exists()) {
293             clientTempDir.mkdirs();
294         }
295         clientTempDir.deleteOnExit();
296 
297         File tempFile = new File(clientTempDir, filename);
298         tempFile.deleteOnExit();
299 
300         return tempFile;
301     }
302 
303     public static File createTempFileFromDocument(CmisObject object, String streamId) throws Exception {
304         ContentStream content = getContentStream(object, streamId);
305         if (content == null) {
306             throw new Exception("No content!");
307         }
308 
309         String filename = content.getFileName();
310         if ((filename == null) || (filename.length() == 0)) {
311             if (object instanceof Document) {
312                 filename = ((Document) object).getContentStreamFileName();
313             }
314         }
315         if ((filename == null) || (filename.length() == 0)) {
316             filename = object.getName();
317         }
318         if ((filename == null) || (filename.length() == 0)) {
319             filename = "content";
320         }
321 
322         String ext = MimeTypes.getExtension(content.getMimeType());
323         if (ext.length() > 0 && !filename.endsWith(ext)) {
324             filename = filename + ext;
325         }
326 
327         File tempFile = ClientHelper.createTempFile(filename);
328         try {
329             storeStream(content.getStream(), tempFile);
330         } catch (CmisConstraintException e) {
331             // there is no content - leave the temp file empty
332         }
333 
334         return tempFile;
335     }
336 
337     private static void storeStream(InputStream in, File file) throws IOException {
338         OutputStream out = null;
339         try {
340             out = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE);
341 
342             byte[] buffer = new byte[BUFFER_SIZE];
343             int b;
344             while ((b = in.read(buffer)) > -1) {
345                 out.write(buffer, 0, b);
346             }
347 
348         } finally {
349             if (in != null) {
350                 try {
351                     in.close();
352                 } catch (Exception e) {
353                 }
354             }
355             if (out != null) {
356                 try {
357                     out.close();
358                 } catch (Exception e) {
359                 }
360             }
361         }
362     }
363 
364     private static ContentStream getContentStream(CmisObject object, String streamId) {
365         if (object == null) {
366             return null;
367         }
368 
369         if (object instanceof Document) {
370             return ((Document) object).getContentStream(streamId);
371         } else {
372             if (streamId == null) {
373                 return null;
374             }
375 
376             List<Rendition> renditions = object.getRenditions();
377             if (renditions == null) {
378                 return null;
379             }
380 
381             for (Rendition rendition : renditions) {
382                 if (streamId.equals(rendition.getStreamId())) {
383                     return rendition.getContentStream();
384                 }
385             }
386         }
387 
388         return null;
389     }
390 
391     public static void copyTableToClipboard(JTable table) {
392         final String newline = System.getProperty("line.separator");
393 
394         final StringBuilder sb = new StringBuilder();
395         final int rows = table.getModel().getRowCount();
396         final int cols = table.getModel().getColumnCount();
397 
398         for (int col = 0; col < cols; col++) {
399             if (col > 0) {
400                 sb.append(",");
401             }
402 
403             sb.append(formatCSVValue(table.getModel().getColumnName(col)));
404         }
405 
406         sb.append(newline);
407 
408         for (int row = 0; row < rows; row++) {
409             for (int col = 0; col < cols; col++) {
410                 if (col > 0) {
411                     sb.append(",");
412                 }
413 
414                 Object value = table.getModel().getValueAt(row, col);
415                 sb.append(formatCSVValue(value));
416             }
417             sb.append(newline);
418         }
419 
420         Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
421         Transferable transferable = new StringSelection(sb.toString());
422         clipboard.setContents(transferable, null);
423     }
424 
425     private static String formatCSVValue(Object value) {
426         if (value == null) {
427             return "";
428         } else if (value instanceof GregorianCalendar) {
429             return getDateString((GregorianCalendar) value);
430         } else if (value instanceof String) {
431             String s = value.toString();
432 
433             StringBuffer sb = new StringBuffer();
434             sb.append('\"');
435 
436             for (int i = 0; i < s.length(); i++) {
437                 char c = s.charAt(i);
438                 sb.append(c);
439                 if (c == '\"') {
440                     sb.append('\"');
441                 }
442             }
443 
444             sb.append('\"');
445 
446             return sb.toString();
447         } else if (value instanceof Collection<?>) {
448             StringBuffer sb = new StringBuffer();
449             sb.append("[");
450 
451             for (Object v : (Collection<?>) value) {
452                 if (sb.length() > 1) {
453                     sb.append(",");
454                 }
455                 sb.append(formatCSVValue(v));
456             }
457 
458             sb.append("]");
459 
460             return sb.toString();
461         } else if (value instanceof ObjectId) {
462             return formatCSVValue(((ObjectId) value).getId());
463         } else if (value instanceof ImageIcon) {
464             return "<icon>";
465         }
466 
467         return value.toString();
468     }
469 
470     public static String readFileAndRemoveHeader(String file) {
471         if (file == null) {
472             return "";
473         }
474 
475         InputStream stream = ClientHelper.class.getResourceAsStream(file);
476         if (stream == null) {
477             return "";
478         } else {
479             try {
480                 BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
481                 StringBuilder sb = new StringBuilder();
482                 String s;
483                 boolean header = true;
484 
485                 while ((s = reader.readLine()) != null) {
486                     // remove header
487                     if (header) {
488                         String st = s.trim();
489                         if (st.length() == 0) {
490                             header = false;
491                             continue;
492                         }
493 
494                         char c = st.charAt(0);
495                         header = (c == '/') || (c == '*') || (c == '#');
496                         if (header) {
497                             continue;
498                         }
499                     }
500 
501                     sb.append(s);
502                     sb.append("\n");
503                 }
504 
505                 reader.close();
506 
507                 return sb.toString();
508             } catch (Exception e) {
509                 return "";
510             }
511         }
512     }
513 
514     public static List<FileEntry> readFileProperties(String propertiesFile, String path) {
515         InputStream stream = ClientHelper.class.getResourceAsStream(propertiesFile);
516         if (stream == null) {
517             return null;
518         }
519 
520         try {
521             Properties properties = new Properties();
522             properties.load(stream);
523             stream.close();
524 
525             List<FileEntry> result = new ArrayList<FileEntry>();
526             for (String file : properties.stringPropertyNames()) {
527                 result.add(new FileEntry(properties.getProperty(file), path + file));
528             }
529             Collections.sort(result);
530 
531             return result;
532         } catch (IOException e) {
533             return null;
534         } finally {
535             try {
536                 stream.close();
537             } catch (IOException ioe) {
538             }
539         }
540     }
541 
542     public static Console openConsole(final Component parent, final ClientModel model, final String file) {
543         try {
544             parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
545 
546             Console console = new Console(parent.getClass().getClassLoader());
547             console.setVariable("session", model.getClientSession().getSession());
548             console.setVariable("binding", model.getClientSession().getSession().getBinding());
549 
550             console.run();
551 
552             JMenu cmisMenu = new JMenu("CMIS");
553             console.getFrame().getRootPane().getJMenuBar().add(cmisMenu);
554 
555             addConsoleMenu(cmisMenu, "CMIS 1.0 Specification", new URI(
556                     "http://docs.oasis-open.org/cmis/CMIS/v1.0/os/cmis-spec-v1.0.html"));
557             addConsoleMenu(cmisMenu, "OpenCMIS Documentation",
558                     new URI("http://chemistry.apache.org/java/opencmis.html"));
559             addConsoleMenu(cmisMenu, "OpenCMIS Client API JavaDoc", new URI(
560                     "http://chemistry.apache.org/java/0.7.0/maven/apidocs/"));
561 
562             console.getInputArea().setText(ClientHelper.readFileAndRemoveHeader(file));
563 
564             return console;
565         } catch (Exception ex) {
566             ClientHelper.showError(null, ex);
567             return null;
568         } finally {
569             parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
570         }
571     }
572 
573     private static void addConsoleMenu(JMenu menu, String title, final URI url) {
574         if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Action.BROWSE)) {
575             return;
576         }
577 
578         JMenuItem menuItem = new JMenuItem(title);
579         menuItem.addActionListener(new ActionListener() {
580             @Override
581             public void actionPerformed(ActionEvent e) {
582                 try {
583                     Desktop.getDesktop().browse(url);
584                 } catch (IOException e1) {
585                 }
586             }
587         });
588 
589         menu.add(menuItem);
590     }
591 
592     public static void runGroovyScript(final Component parent, final ClientModel model, final File file,
593             final Writer out) {
594         try {
595             parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
596 
597             String[] roots = new String[] { file.getParentFile().getAbsolutePath() };
598             GroovyScriptEngine gse = new GroovyScriptEngine(roots, parent.getClass().getClassLoader());
599             Binding binding = new Binding();
600             binding.setVariable("session", model.getClientSession().getSession());
601             binding.setVariable("binding", model.getClientSession().getSession().getBinding());
602             binding.setVariable("out", out);
603             gse.run(file.getName(), binding);
604         } catch (Exception ex) {
605             ClientHelper.showError(null, ex);
606         } finally {
607             parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
608         }
609     }
610 
611     public static void runJSR223Script(final Component parent, final ClientModel model, final File file,
612             final String ext, final Writer out) {
613         try {
614             parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
615 
616             ScriptEngineManager mgr = new ScriptEngineManager();
617             ScriptEngine engine = mgr.getEngineByExtension(ext);
618             engine.getContext().setWriter(out);
619             engine.getContext().setErrorWriter(out);
620             engine.put("session", model.getClientSession().getSession());
621             engine.put("binding", model.getClientSession().getSession().getBinding());
622             engine.put("out", new PrintWriter(out));
623             engine.eval(new FileReader(file));
624         } catch (Exception ex) {
625             ClientHelper.showError(null, ex);
626         } finally {
627             parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
628         }
629     }
630 
631     public static class FileEntry implements Comparable<FileEntry> {
632         private final String name;
633         private final String file;
634 
635         public FileEntry(String name, String file) {
636             this.name = name;
637             this.file = file;
638         }
639 
640         public String getName() {
641             return name;
642         }
643 
644         public String getFile() {
645             return file;
646         }
647 
648         @Override
649         public String toString() {
650             return name;
651         }
652 
653         @Override
654         public int compareTo(FileEntry o) {
655             return name.compareToIgnoreCase(o.getName());
656         }
657 
658         @Override
659         public int hashCode() {
660             return name.hashCode();
661         }
662 
663         @Override
664         public boolean equals(Object obj) {
665             if (!(obj instanceof FileEntry)) {
666                 return false;
667             }
668 
669             return name.equals(((FileEntry) obj).getName());
670         }
671     }
672 }