KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > xsl > transform > TransformPerformer


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.xsl.transform;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.StringWriter JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.util.*;
26 import java.net.URL JavaDoc;
27 import java.net.MalformedURLException JavaDoc;
28 import java.net.UnknownHostException JavaDoc;
29 import java.awt.Dialog JavaDoc;
30 import java.awt.event.ActionListener JavaDoc;
31 import java.awt.event.ActionEvent JavaDoc;
32 import java.awt.event.WindowAdapter JavaDoc;
33 import java.awt.event.WindowEvent JavaDoc;
34 import java.beans.PropertyVetoException JavaDoc;
35
36 import org.openide.cookies.SaveCookie;
37
38 import org.xml.sax.*;
39 import javax.xml.parsers.*;
40 import javax.xml.transform.*;
41 import javax.xml.transform.sax.*;
42 import javax.xml.transform.stream.*;
43
44 import org.openide.*;
45 import org.openide.awt.HtmlBrowser;
46 import org.openide.filesystems.*;
47 import org.openide.nodes.Node;
48 import org.openide.loaders.DataObject;
49 import org.openide.util.HelpCtx;
50 import org.openide.util.RequestProcessor;
51 import org.openide.util.Task;
52 import org.openide.util.actions.CookieAction;
53
54 import org.netbeans.api.xml.cookies.*;
55
56 import org.netbeans.modules.xml.core.XMLDataObject;
57 import org.netbeans.modules.xml.core.actions.CollectXMLAction;
58 import org.netbeans.modules.xml.core.actions.InputOutputReporter;
59
60 import org.netbeans.modules.xml.core.lib.GuiUtil;
61 import org.netbeans.modules.xml.core.lib.FileUtilities;
62
63 import org.netbeans.modules.xsl.XSLDataObject;
64 import org.netbeans.modules.xsl.ui.TransformPanel;
65 import org.netbeans.modules.xsl.settings.TransformHistory;
66 import org.netbeans.modules.xsl.actions.TransformAction;
67 import org.netbeans.modules.xsl.utils.TransformUtil;
68 import org.openide.loaders.DataObjectNotFoundException;
69
70 /**
71  * Handle workflow of transformation action, gather UI info and
72  * launch the processor.
73  * <p>
74  * This class has very/needlessly complicated workflow.
75  *
76  * @author Libor Kramolis
77  * @version 0.1
78  */

79 public class TransformPerformer {
80     /** Represent transformation output window. */
81     private InputOutputReporter cookieObserver = null;
82     private Node[] nodes;
83     
84     // instance freshness state
85
private volatile boolean stalled = false;
86     private volatile boolean active = true;
87     
88     public TransformPerformer(Node[] nodes) {
89         this.nodes = nodes;
90     }
91     
92     /** If the Data Object is modified, then is saved.
93      * Fix for issue #61608
94      */

95     private void saveBeforeTransformation (DataObject dObject){
96         if (dObject.isModified()){
97             SaveCookie save;
98             save = (SaveCookie)dObject.getCookie(SaveCookie.class);
99             if (save != null) {
100                 try {
101                     save.save();
102                 } catch (IOException JavaDoc ex) {
103                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
104                 }
105             }
106         }
107     }
108     
109     /**
110      * Entry point called from transform action.
111      * There is a fresh instance per call.
112      */

113     public void perform() {
114         
115         if (stalled) throw new IllegalStateException JavaDoc();
116         
117         try {
118             if ( nodes.length == 2 ) {
119                 
120                 // automatically detect if one of selected nodes is transformation
121
// in such case suppose that user want to it to transform second file
122

123                 DataObject do1 = (DataObject) nodes[0].getCookie(DataObject.class);
124                 boolean xslt1 = TransformUtil.isXSLTransformation(do1);
125                 DataObject do2 = (DataObject) nodes[1].getCookie(DataObject.class);
126                 boolean xslt2 = TransformUtil.isXSLTransformation(do2);
127                 
128                 // fix for issue #61608
129
saveBeforeTransformation(do1);
130                 saveBeforeTransformation(do2);
131                 
132                 if ( Util.THIS.isLoggable() ) /* then */ {
133                     Util.THIS.debug("TransformAction.performAction:");
134                     Util.THIS.debug(" do1 [" + xslt1 + "] = " + do1);
135                     Util.THIS.debug(" do2 [" + xslt2 + "] = " + do2);
136                 }
137                 
138                 if ( xslt1 != xslt2 ) {
139                     TransformableCookie transformable;
140                     DataObject xmlDO;
141                     DataObject xslDO;
142                     if ( xslt1 ) {
143                         transformable = (TransformableCookie) nodes[1].getCookie(TransformableCookie.class);
144                         xmlDO = do2;
145                         xslDO = do1;
146                     } else {
147                         transformable = (TransformableCookie) nodes[0].getCookie(TransformableCookie.class);
148                         xmlDO = do1;
149                         xslDO = do2;
150                     }
151                     DoublePerformer performer = new DoublePerformer(transformable, xmlDO, xslDO);
152                     performer.perform();
153                 } else {
154                     TransformableCookie transformable1 = (TransformableCookie) nodes[0].getCookie(TransformableCookie.class);
155                     SinglePerformer performer = new SinglePerformer(transformable1, do1, xslt1);
156                     performer.setLastInBatch(false);
157                     performer.perform();
158                     
159                     TransformableCookie transformable2 = (TransformableCookie) nodes[1].getCookie(TransformableCookie.class);
160                     performer = new SinglePerformer(transformable2, do2, xslt2);
161                     performer.perform();
162                 }
163             } else { // nodes.length != 2
164
for ( int i = 0; i < nodes.length; i++ ) {
165                     DataObject dataObject = (DataObject) nodes[i].getCookie(DataObject.class);
166                     // fix for issue #61608
167
saveBeforeTransformation(dataObject);
168                     TransformableCookie transformable = null;
169                     boolean xslt = TransformUtil.isXSLTransformation(dataObject);
170                     if ( xslt == false ) {
171                         transformable = (TransformableCookie) nodes[i].getCookie(TransformableCookie.class);
172                     }
173                     SinglePerformer performer = new SinglePerformer(transformable, dataObject, xslt);
174                     performer.setLastInBatch(i == (nodes.length -1));
175                     performer.perform();
176                 }
177             }
178         } finally {
179             stalled = true;
180         }
181     }
182     
183     /**
184      * Is still running
185      */

186     public boolean isActive() {
187         return active;
188     }
189     
190     /**
191      * Always return an instance. Shareable by all children nested performers.
192      */

193     private InputOutputReporter getCookieObserver() {
194         if ( cookieObserver == null ) {
195             String JavaDoc label = Util.THIS.getString("PROP_transformation_io_name");
196             cookieObserver = new InputOutputReporter(label);
197         }
198         return cookieObserver;
199     }
200     
201     
202     //
203
// class AbstractPerformer
204
//
205

206     private abstract class AbstractPerformer extends WindowAdapter JavaDoc implements ActionListener JavaDoc {
207         // if called on TransformableCookie node
208
private TransformableCookie transformableCookie;
209         // input XML source DataObject
210
protected DataObject xmlDO;
211         // <?xml-stylesheet
212
protected Source xmlStylesheetSource;
213         // input XSLT script DataObject
214
protected DataObject xslDO;
215         // used to resolve relative path
216
protected FileObject baseFO;
217         // URL of base FileObject
218
protected URL JavaDoc baseURL;
219         // XML Source
220
private Source xmlSource;
221         // XSLT Source
222
private Source xslSource;
223         // Result FileObject
224
private FileObject resultFO;
225         
226         private TransformPanel transformPanel;
227         private DialogDescriptor dialogDescriptor;
228         private Dialog JavaDoc dialog;
229         
230         private TransformPanel.Data data;
231         private boolean last = true;
232         
233         // was window closed by
234
private boolean workaround31850 = true;
235         
236         
237         public AbstractPerformer(TransformableCookie transformable) {
238             this.transformableCookie = transformable;
239         }
240         
241         
242         /**
243          * It shows a dialog and let user selct his options. Then it performs them.
244          */

245         public final void perform() {
246             try {
247                 init(); // throws IOException
248
showDialog(); // throws IOException
249
} catch (IOException JavaDoc exc) {
250                 if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(exc);
251                 
252                 NotifyDescriptor nd = new NotifyDescriptor.Message(exc.getLocalizedMessage(), NotifyDescriptor.WARNING_MESSAGE);
253                 DialogDisplayer.getDefault().notify(nd);
254                 
255                 if (isLastInBatch()) {
256                     active = false;
257                 }
258             }
259         }
260         
261         protected abstract void init() throws IOException JavaDoc;
262         
263         protected abstract void storeData();
264         
265         private void showDialog() throws IOException JavaDoc {
266             String JavaDoc xmlStylesheetName = null;
267             if ( xmlStylesheetSource != null ) {
268                 xmlStylesheetName = xmlStylesheetSource.getSystemId();
269             }
270             transformPanel = new TransformPanel(xmlDO, xmlStylesheetName, xslDO);
271             
272             dialogDescriptor = new DialogDescriptor(transformPanel,
273                     Util.THIS.getString("NAME_transform_panel_title"), true,
274                     DialogDescriptor.OK_CANCEL_OPTION, DialogDescriptor.OK_OPTION,
275                     DialogDescriptor.BOTTOM_ALIGN,
276                     new HelpCtx(TransformAction.class), null);
277             dialogDescriptor.setClosingOptions(new Object JavaDoc[] { DialogDescriptor.CANCEL_OPTION });
278             dialogDescriptor.setButtonListener(this);
279             
280             dialog = DialogDisplayer.getDefault().createDialog(dialogDescriptor);
281             dialog.addWindowListener(this); // #31850 workaround
282
dialog.show();
283         }
284         
285         protected void prepareData() throws IOException JavaDoc, FileStateInvalidException, MalformedURLException JavaDoc, ParserConfigurationException, SAXException {
286             data = transformPanel.getData();
287             
288             if ( Util.THIS.isLoggable() ) /* then */ {
289                 Util.THIS.debug("TransformPerformer...performTransformation");
290                 Util.THIS.debug(" transformable = " + transformableCookie);
291                 Util.THIS.debug(" baseFileObject = " + baseFO);
292                 Util.THIS.debug(" data = " + data);
293             }
294             
295             try {
296                 xmlSource = TransformUtil.createSource(baseURL, data.getInput()); // throws IOException, MalformedURLException, FileStateInvalidException, ParserConfigurationException, SAXException
297
} catch (IOException JavaDoc ex) {
298                 ErrorManager.getDefault().annotate(ex, Util.THIS.getString("MSG_sourceError"));
299                 throw ex;
300             }
301             if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" xmlSource = " + xmlSource.getSystemId());
302             
303             if ( data.getXSL() != null ) {
304                 try {
305                     xslSource = TransformUtil.createSource(baseURL, data.getXSL()); // throws IOException, MalformedURLException, FileStateInvalidException, ParserConfigurationException, SAXException
306
} catch (IOException JavaDoc ex) {
307                     ErrorManager.getDefault().annotate(ex, Util.THIS.getString("MSG_transError"));
308                     throw ex;
309                 }
310             } else {
311                 xslSource = xmlStylesheetSource;
312             }
313             
314             if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" xslSource = " + xslSource.getSystemId());
315             
316             if ( data.getOutput() != null ) { // not Preview
317
String JavaDoc fileName = data.getOutput().toString().replace('\\', '/');
318                 try {
319                     resultFO = FileUtilities.createFileObject(baseFO.getParent(), fileName, data.isOverwriteOutput()); // throws IOException
320
} catch (IOException JavaDoc ex) {
321                     ErrorManager.getDefault().annotate(ex, Util.THIS.getString("MSG_resultError"));
322                     throw ex;
323                 }
324                 
325                 if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(" resultFO = " + resultFO);
326             }
327         }
328         
329         protected void updateHistory(DataObject dataObject, boolean xslt) {
330             FileObject fileObject = dataObject.getPrimaryFile();
331             TransformHistory history = (TransformHistory) fileObject.getAttribute(TransformHistory.TRANSFORM_HISTORY_ATTRIBUTE);
332             if ( history == null ) {
333                 history = new TransformHistory();
334             }
335             String JavaDoc outputStr=null;
336             if(data.getOutput()!=null) {
337                 outputStr=data.getOutput().toString();
338             }
339             if ( xslt ) {
340                 history.addXML(data.getInput(), outputStr);
341             } else {
342                 history.addXSL(data.getXSL(), outputStr);
343             }
344             history.setOverwriteOutput(data.isOverwriteOutput());
345             history.setProcessOutput(data.getProcessOutput());
346             
347             try {
348                 fileObject.setAttribute(TransformHistory.TRANSFORM_HISTORY_ATTRIBUTE, history);
349             } catch (IOException JavaDoc exc) {
350                 // ... will not be persistent!
351
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, exc);
352             }
353         }
354         
355         /**
356          * Inicializes a servet and then provokes it by opening browser poiting to it.
357          * External XSLT processor is called from the servlet.
358          */

359         private void previewOutput() throws MalformedURLException JavaDoc, UnknownHostException JavaDoc {
360             TransformServlet.prepare(transformableCookie, xmlSource, xslSource);
361             showURL(TransformServlet.getServletURL());
362         }
363         
364         /**
365          * External XSLT processor is called from this method.
366          */

367         private void fileOutput() throws IOException JavaDoc, FileStateInvalidException, TransformerException {
368             OutputStream JavaDoc outputStream = null;
369             FileLock fileLock = null;
370             try {
371                 fileLock = resultFO.lock();
372                 outputStream = resultFO.getOutputStream(fileLock);
373                 
374                 Result outputResult = new StreamResult(outputStream); // throws IOException, FileStateInvalidException
375

376                 if ( Util.THIS.isLoggable() ) /* then */ {
377                     Util.THIS.debug(" resultFO = " + resultFO);
378                     Util.THIS.debug(" outputResult = " + outputResult);
379                 }
380                 
381                 String JavaDoc xmlName = data.getInput();
382                 String JavaDoc xslName = data.getXSL();
383                 TransformPerformer.this.getCookieObserver().message(Util.THIS.getString("MSG_transformation_1", xmlName, xslName));
384                 TransformUtil.transform(xmlSource, transformableCookie, xslSource, outputResult, TransformPerformer.this.getCookieObserver()); // throws TransformerException
385

386                 // revalidate DataObject associated with possibly partially written file #28079
387
try {
388                     DataObject dataObject = DataObject.find(resultFO);
389                     dataObject.setValid(false);
390                 } catch (DataObjectNotFoundException dnf) {
391                     throw new IllegalStateException JavaDoc();
392                 } catch (PropertyVetoException JavaDoc pve) {
393                     ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "Cannot invalidate " + resultFO);
394                 }
395                 
396                 if ( data.getProcessOutput() == TransformHistory.APPLY_DEFAULT_ACTION ) {
397                     GuiUtil.performDefaultAction(resultFO);
398                     GuiUtil.performDefaultAction(resultFO);
399                 } else if ( data.getProcessOutput() == TransformHistory.OPEN_IN_BROWSER ) {
400                     showURL(resultFO.getURL());
401                 }
402             } catch (FileAlreadyLockedException exc) {
403                 throw (FileAlreadyLockedException) ErrorManager.getDefault().annotate(exc, Util.THIS.getString("ERR_FileAlreadyLockedException_output"));
404             } finally {
405                 if ( outputStream != null ) {
406                     outputStream.close();
407                 }
408                 if ( fileLock != null ) {
409                     fileLock.releaseLock();
410                 }
411             }
412         }
413         
414         private void showURL(URL JavaDoc url) {
415             HtmlBrowser.URLDisplayer.getDefault().showURL(url);
416             GuiUtil.setStatusText(Util.THIS.getString("MSG_opening_browser"));
417         }
418         
419         
420         //
421
// from ActionListener
422
//
423

424         public final void actionPerformed(ActionEvent JavaDoc e) {
425             if ( Util.THIS.isLoggable() ) /* then */ {
426                 Util.THIS.debug("[TransformPerformer::AbstractPerformer] actionPerformed: " + e);
427                 Util.THIS.debug(" ActionEvent.getSource(): " + e.getSource());
428             }
429             
430             workaround31850 = false;
431             if ( DialogDescriptor.OK_OPTION.equals(e.getSource()) ) {
432                 try {
433                     prepareData(); // throws IOException(, FileStateInvalidException, MalformedURLException), ParserConfigurationException, SAXException
434

435                     if ( ( data.getOutput() != null ) &&
436                             ( resultFO == null ) ) {
437                         return;
438                     }
439                     
440                     dialog.dispose();
441                     storeData();
442                     async();
443                     
444                 } catch (Exception JavaDoc exc) { // IOException, ParserConfigurationException, SAXException
445
// during prepareData(), previewOutput() and fileOutput()
446
if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(exc);
447                     
448                     // NotifyDescriptor nd = new NotifyDescriptor.Message (exc.getLocalizedMessage(), NotifyDescriptor.WARNING_MESSAGE);
449
// TopManager.getDefault().notify (nd);
450

451                     ErrorManager.getDefault().notify(ErrorManager.WARNING, exc);
452                     if (isLastInBatch()) {
453                         active = false;
454                     }
455                 }
456             } else {
457                 active = false;
458             }
459         }
460         
461         // WindowAdapter #31850 workaround
462
public void windowClosed(WindowEvent JavaDoc e) {
463             super.windowClosed(e);
464             if (workaround31850) {
465                 active = false;
466             }
467         }
468         
469         /**
470          * Perform the transformatin itself asynchronously ... (#29614)
471          */

472         private void async() {
473             RequestProcessor rp = RequestProcessor.getDefault();
474             rp.post(new Runnable JavaDoc() {
475                 public void run() {
476                     try {
477                         if ( data.getOutput() == null ) { // Preview
478
previewOutput(); // throws IOException (MalformedURLException, UnknownHostException)
479
} else {
480                             fileOutput(); // throws IOException(, FileStateInvalidException), TransformerException
481
}
482                     } catch (TransformerException exc) { // during fileOutput();
483
// ignore it -> it should be displayed by CookieObserver!
484
} catch (Exception JavaDoc exc) { // IOException, ParserConfigurationException, SAXException
485
// during prepareData(), previewOutput() and fileOutput()
486
if ( Util.THIS.isLoggable() ) /* then */ Util.THIS.debug(exc);
487                         
488                         // NotifyDescriptor nd = new NotifyDescriptor.Message (exc.getLocalizedMessage(), NotifyDescriptor.WARNING_MESSAGE);
489
// TopManager.getDefault().notify (nd);
490

491                         ErrorManager.getDefault().notify(ErrorManager.WARNING, exc);
492                     } finally {
493                         if (isLastInBatch()) {
494                             InputOutputReporter cookieObserver = getCookieObserver();
495                             if ( cookieObserver != null ) {
496                                 cookieObserver.message(Util.THIS.getString("MSG_transformation_2"));
497                                 cookieObserver.moveToFront(true);
498                             }
499                             active = false;
500                         }
501                     }
502                 }
503             });
504         }
505         
506         
507         /**
508          * If possible it finds "file:" URL if <code>fileObject</code> is on LocalFileSystem.
509          * @return URL of <code>fileObject</code>.
510          */

511         protected URL JavaDoc preferFileURL(FileObject fileObject) throws MalformedURLException JavaDoc, FileStateInvalidException {
512             URL JavaDoc fileURL = null;
513             File JavaDoc file = FileUtil.toFile(fileObject);
514             
515             if ( file != null ) {
516                 fileURL = file.toURL();
517             } else {
518                 fileURL = fileObject.getURL();
519             }
520             return fileURL;
521         }
522         
523         public final void setLastInBatch(boolean last) {
524             this.last = last;
525         }
526         
527         /**
528          * Return if caller uses more perfomers and this one is the last one.
529          */

530         public final boolean isLastInBatch() {
531             return last;
532         }
533     } // class AbstractPerformer
534

535     
536     //
537
// class SinglePerformer
538
//
539

540     private class SinglePerformer extends AbstractPerformer {
541         private DataObject dataObject;
542         private boolean xslt;
543         
544         public SinglePerformer(TransformableCookie transformable, DataObject dataObject, boolean xslt) {
545             super(transformable);
546             
547             this.dataObject = dataObject;
548             this.xslt = xslt;
549         }
550         
551         /**
552          * @throws FileStateInvalidException from baseFO.getURL();
553          */

554         protected void init() throws IOException JavaDoc {
555             baseFO = dataObject.getPrimaryFile();
556             baseURL = preferFileURL(baseFO);
557             
558             if ( xslt ) {
559                 xmlDO = null;
560                 xmlStylesheetSource = null;
561                 xslDO = dataObject;
562             } else {
563                 xmlDO = dataObject;
564                 xmlStylesheetSource = TransformUtil.getAssociatedStylesheet(baseURL);
565                 xslDO = null;
566             }
567         }
568         
569         protected void storeData() {
570             updateHistory(dataObject, xslt);
571         }
572         
573     } // class SinglePerformer
574

575     
576     //
577
// class DoublePerformer
578
//
579

580     private class DoublePerformer extends AbstractPerformer {
581         
582         public DoublePerformer(TransformableCookie transformable, DataObject xmlDO, DataObject xslDO) {
583             super(transformable);
584             
585             this.xmlDO = xmlDO;
586             this.xslDO = xslDO;
587         }
588         
589         /**
590          * @throws FileStateInvalidException from baseFO.getURL();
591          */

592         protected void init() throws IOException JavaDoc {
593             baseFO = xmlDO.getPrimaryFile();
594             baseURL = preferFileURL(baseFO);
595         }
596         
597         protected void storeData() {
598             updateHistory(xmlDO, false);
599             updateHistory(xslDO, true);
600         }
601         
602         
603     } // class DoublePerformer
604

605 }
606
Popular Tags