View Javadoc
1   package org.andromda.core.transformation;
2   
3   import java.io.ByteArrayInputStream;
4   import java.io.ByteArrayOutputStream;
5   import java.io.File;
6   import java.io.FileOutputStream;
7   import java.io.InputStream;
8   import java.net.URL;
9   import java.util.Arrays;
10  import java.util.Collection;
11  import java.util.Iterator;
12  import javax.xml.transform.Result;
13  import javax.xml.transform.Source;
14  import javax.xml.transform.TransformerException;
15  import javax.xml.transform.TransformerFactory;
16  import javax.xml.transform.URIResolver;
17  import javax.xml.transform.stream.StreamResult;
18  import javax.xml.transform.stream.StreamSource;
19  import org.andromda.core.common.AndroMDALogger;
20  import org.andromda.core.common.ResourceUtils;
21  import org.andromda.core.configuration.Transformation;
22  import org.apache.commons.lang.StringUtils;
23  
24  /**
25   * An implementation of Transformer that provides
26   * XSLT transformations.  The {@link #transform(String, Transformation[])}
27   * operation will apply the given XSLT files to the model
28   * in the order which they are found.
29   *
30   * @author Chad Brandon
31   */
32  public class XslTransformer
33      implements Transformer
34  {
35      /**
36       * Applies the given XSLT files to the model in the order in which they are found.
37       *
38       * @see org.andromda.core.transformation.Transformer#transform(String, org.andromda.core.configuration.Transformation[])
39       */
40      public InputStream transform(
41          final String modelUri,
42          final Transformation[] xsltTransformations)
43      {
44          try
45          {
46              InputStream stream = null;
47              if (StringUtils.isNotBlank(modelUri))
48              {
49                  final URL modelUrl = new URL(modelUri);
50                  if (xsltTransformations != null && xsltTransformations.length > 0)
51                  {
52                      Source modelSource = new StreamSource(modelUrl.openStream());
53                      final Collection<Transformation> xslts = Arrays.asList(xsltTransformations);
54                      final TransformerFactory factory = TransformerFactory.newInstance();
55                      final TransformerURIResolver resolver = new TransformerURIResolver();
56                      factory.setURIResolver(resolver);
57                      for (final Iterator<Transformation> xsltIterator = xslts.iterator(); xsltIterator.hasNext();)
58                      {
59                          final Transformation transformation = xsltIterator.next();
60                          final URL xslt = new URL(transformation.getUri());
61                          resolver.setLocation(xslt);
62                          AndroMDALogger.info("Applying transformation --> '" + xslt + '\'');
63                          final Source xsltSource = new StreamSource(xslt.openStream());
64                          final javax.xml.transform.Transformer transformer = factory.newTransformer(xsltSource);
65                          final ByteArrayOutputStream output = new ByteArrayOutputStream();
66                          final Result result = new StreamResult(output);
67                          transformer.transform(modelSource, result);
68                          final byte[] outputResult = output.toByteArray();
69                          stream = new ByteArrayInputStream(outputResult);
70  
71                          // if we have an output location specified, write the result
72                          final String outputLocation = transformation.getOutputLocation();
73                          if (StringUtils.isNotBlank(outputLocation))
74                          {
75                              final File fileOutput = new File(outputLocation);
76                              final File parent = fileOutput.getParentFile();
77                              if (parent != null)
78                              {
79                                  parent.mkdirs();
80                              }
81                              FileOutputStream outputStream = new FileOutputStream(fileOutput);
82                              AndroMDALogger.info("Transformation output: '" + outputLocation + '\'');
83                              outputStream.write(outputResult);
84                              outputStream.flush();
85                              outputStream.close();
86                          }
87                          if (xsltIterator.hasNext())
88                          {
89                              modelSource = new StreamSource(stream);
90                          }
91                      }
92                  }
93                  else
94                  {
95                      stream = modelUrl.openStream();
96                  }
97              }
98              return stream;
99          }
100         catch (final Exception exception)
101         {
102             throw new XslTransformerException(exception);
103         }
104     }
105 
106     /**
107      * Provides the URI resolving capabilities for the
108      * {@link XslTransformer}
109      */
110     static final class TransformerURIResolver
111         implements URIResolver
112     {
113         /**
114          * @see javax.xml.transform.URIResolver#resolve(String, String)
115          */
116         public Source resolve(
117             final String href,
118             final String base)
119             throws TransformerException
120         {
121             Source source = null;
122             if (this.location != null)
123             {
124                 String locationUri = ResourceUtils.normalizePath(this.location.toString());
125                 locationUri = locationUri.substring(0, locationUri.lastIndexOf('/') + 1);
126                 source = new StreamSource(locationUri + href);
127             }
128             return source;
129         }
130 
131         /**
132          * The current transformation location.
133          */
134         private URL location;
135 
136         /**
137          * Sets the location of the current transformation.
138          *
139          * @param location the transformation location as a URI.
140          */
141         public void setLocation(URL location)
142         {
143             this.location = location;
144         }
145     }
146 }