001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.resource;
018
019import java.io.ByteArrayInputStream;
020import java.io.ByteArrayOutputStream;
021import java.io.IOException;
022import java.io.InputStream;
023import java.time.Instant;
024import java.util.Map;
025import java.util.Map.Entry;
026import org.apache.wicket.util.io.IOUtils;
027import org.apache.wicket.util.lang.Bytes;
028
029/**
030 * {@link IResourceStream} that applies XSLT on an input {@link IResourceStream}. The XSL stylesheet
031 * itself is also an {@link IResourceStream}. Override {@link #getParameters()} to pass parameters
032 * to the XSL stylesheet.
033 * 
034 * <p>
035 * NOTE: this is an experimental feature which does not implement any kind of caching, use with
036 * care, running an XSL transformation for every request is very expensive! Please have a look at
037 * {@link ZipResourceStream} for an in-depth explanation of what needs to be done with respect to
038 * caching.
039 * </p>
040 * 
041 * @author <a href="mailto:jbq@apache.org">Jean-Baptiste Quenot</a>
042 */
043public class XSLTResourceStream extends AbstractResourceStream
044{
045        /**
046         * 
047         */
048        private static final long serialVersionUID = 1L;
049        private final transient ByteArrayOutputStream out;
050
051        /**
052         * @return a {@link Map} of XSLT parameters, appropriate for passing information to the XSL
053         *         stylesheet
054         */
055        protected Map<Object, Object> getParameters()
056        {
057                return null;
058        }
059
060        /**
061         * Construct.
062         * 
063         * @param xsltResource
064         *            the XSL stylesheet as an {@link IResourceStream}
065         * @param xmlResource
066         *            the input XML document as an {@link IResourceStream}
067         */
068        public XSLTResourceStream(final IResourceStream xsltResource, final IResourceStream xmlResource)
069        {
070                try
071                {
072                        javax.xml.transform.Source xmlSource = new javax.xml.transform.stream.StreamSource(
073                                xmlResource.getInputStream());
074                        javax.xml.transform.Source xsltSource = new javax.xml.transform.stream.StreamSource(
075                                xsltResource.getInputStream());
076                        out = new ByteArrayOutputStream();
077                        javax.xml.transform.Result result = new javax.xml.transform.stream.StreamResult(out);
078
079                        // create an instance of TransformerFactory
080                        javax.xml.transform.TransformerFactory transFact = javax.xml.transform.TransformerFactory.newInstance();
081
082                        javax.xml.transform.Transformer trans = transFact.newTransformer(xsltSource);
083                        Map<Object, Object> parameters = getParameters();
084                        if (parameters != null)
085                        {
086                                for (Entry<Object, Object> e : parameters.entrySet())
087                                {
088                                        trans.setParameter(e.getKey().toString(), e.getValue().toString());
089                                }
090                        }
091
092                        trans.transform(xmlSource, result);
093                }
094                catch (Exception e)
095                {
096                        throw new RuntimeException(e);
097                }
098                finally
099                {
100                        IOUtils.closeQuietly(xmlResource);
101                        IOUtils.closeQuietly(xsltResource);
102                }
103        }
104
105        /**
106         * @see org.apache.wicket.util.resource.IResourceStream#close()
107         */
108        @Override
109        public void close() throws IOException
110        {
111        }
112
113        /**
114         * Returns always null
115         * 
116         * @see org.apache.wicket.util.resource.IResourceStream#getContentType()
117         */
118        @Override
119        public String getContentType()
120        {
121                return null;
122        }
123
124        /**
125         * @see org.apache.wicket.util.resource.IResourceStream#getInputStream()
126         */
127        @Override
128        public InputStream getInputStream() throws ResourceStreamNotFoundException
129        {
130                return new ByteArrayInputStream(out.toByteArray());
131        }
132
133        /**
134         * @see org.apache.wicket.util.resource.IResourceStream#length()
135         */
136        @Override
137        public Bytes length()
138        {
139                return Bytes.bytes(out.size());
140        }
141
142        /**
143         * Returns always null
144         * 
145         * @see org.apache.wicket.util.watch.IModifiable#lastModifiedTime()
146         */
147        @Override
148        public Instant lastModifiedTime()
149        {
150                return null;
151        }
152
153}