001    
002    /*
003     * Copyright (C) 2012 Archie L. Cobbs. All rights reserved.
004     *
005     * $Id: SpringXSLPersistentObjectSchemaUpdate.java 240 2012-01-19 19:42:54Z archie.cobbs $
006     */
007    
008    package org.dellroad.stuff.pobj;
009    
010    import java.io.IOException;
011    import java.io.InputStream;
012    import java.util.Properties;
013    
014    import javax.xml.transform.Transformer;
015    import javax.xml.transform.TransformerException;
016    import javax.xml.transform.TransformerFactory;
017    import javax.xml.transform.stream.StreamSource;
018    
019    import org.dellroad.stuff.xml.TransformErrorListener;
020    import org.slf4j.LoggerFactory;
021    import org.springframework.core.io.Resource;
022    
023    /**
024     * {@link SpringPersistentObjectSchemaUpdate} that applies a configured XSL transform to the XML form of the persistent object.
025     *
026     * <p>
027     * The {@link #setTransform transform} property is required.
028     *
029     * <p>
030     * See {@link SpringPersistentObjectSchemaUpdater} for a Spring configuration example.
031     *
032     * @param <T> type of the persistent object
033     */
034    public class SpringXSLPersistentObjectSchemaUpdate<T> extends SpringPersistentObjectSchemaUpdate<T> {
035    
036        private Resource transform;
037        private Properties parameters;
038    
039        @Override
040        public void afterPropertiesSet() throws Exception {
041            super.afterPropertiesSet();
042            if (this.transform == null)
043                throw new Exception("no transform configured");
044        }
045    
046        /**
047         * Configure the XSLT transform as a resource.
048         */
049        public void setTransform(Resource transform) {
050            this.transform = transform;
051        }
052    
053        public Resource getTransform() {
054            return this.transform;
055        }
056    
057        /**
058         * Configure XSLT parameters. This is an optional property.
059         */
060        public void setParameters(Properties properties) {
061            this.parameters = parameters;
062        }
063    
064        /**
065         * Apply this update to the given transaction.
066         */
067        @Override
068        public void apply(PersistentFileTransaction transaction) {
069    
070            // Get transform source
071            InputStream input;
072            try {
073                input = this.transform.getInputStream();
074            } catch (IOException e) {
075                throw new RuntimeException(e);
076            }
077            try {
078    
079                // Setup transformer
080                Transformer transformer = TransformerFactory.newInstance().newTransformer(
081                  new StreamSource(input, this.transform.getURI().toString()));
082                transformer.setErrorListener(new TransformErrorListener(LoggerFactory.getLogger(this.getClass()), true));
083                if (this.parameters != null) {
084                    for (String name : this.parameters.stringPropertyNames())
085                        transformer.setParameter(name, this.parameters.getProperty(name));
086                }
087    
088                // Do the transform
089                transaction.transform(transformer);
090    
091            } catch (IOException e) {
092                throw new RuntimeException(e);
093            } catch (TransformerException e) {
094                throw new RuntimeException(e);
095            } catch (RuntimeException e) {
096                if (e.getCause() instanceof TransformerException && e.getCause().getCause() instanceof RuntimeException)
097                    e = (RuntimeException)e.getCause().getCause();
098                throw e;
099            } finally {
100                try {
101                    input.close();
102                } catch (IOException e) {
103                    // ignore
104                }
105            }
106        }
107    }
108