Package org.geoserver.wfs.xslt.config

Source Code of org.geoserver.wfs.xslt.config.TransformRepository

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs.xslt.config;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.impl.FeatureTypeInfoImpl;
import org.geoserver.config.GeoServerDataDirectory;
import org.geoserver.wfs.WFSException;
import org.geotools.util.logging.Logging;

import com.thoughtworks.xstream.XStream;

/**
* Manages access to the XLST transformation definitions
*
* @author Andrea Aime - GeoSolutions
*/
public class TransformRepository {

    static final Logger LOGGER = Logging.getLogger(TransformRepository.class);

    static final FilenameFilter CONFIG_NAME_FILTER = new SuffixFileFilter(".xml");

    XStream xs;

    GeoServerDataDirectory dataDir;

    /**
     * Caches the {@link TransformInfo} objects so that we don't have to load them from disk all the time
     */
    FileItemCache<TransformInfo> infoCache = new FileItemCache<TransformInfo>(100) {

        @Override
        protected TransformInfo loadItem(File file) throws IOException {
            if(!file.exists()) {
                return null;
            }
           
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                TransformInfo info = (TransformInfo) xs.fromXML(fis);
                info.setName(getTransformName(file));

                return info;
            } finally {
                IOUtils.closeQuietly(fis);
            }
        }
    };
   
    /**
     * Caches the XSLT Templates to avoid parsing the XSLT over and over (Templates is thread safe,
     * {@link Transformer} is not.
     */
    FileItemCache<Templates> transformCache = new FileItemCache<Templates>(100) {
       
        @Override
        protected Templates loadItem(File file) throws IOException {
            try {
                Source xslSource = new StreamSource(file);
               
                TransformerFactory tf = TransformerFactory.newInstance( );
                final List<TransformerException> errors = new ArrayList<TransformerException>();
                tf.setErrorListener(new ErrorListener() {
                   
                    @Override
                    public void warning(TransformerException e) throws TransformerException {
                        LOGGER.log(Level.WARNING, "Found warning while loading XSLT template", e);
                       
                    }
                   
                    @Override
                    public void fatalError(TransformerException e) throws TransformerException {
                        errors.add(e);
                    }
                   
                    @Override
                    public void error(TransformerException e) throws TransformerException {
                        errors.add(e);
                       
                    }
                });
                Templates template = tf.newTemplates(xslSource);
               
                if(errors.size() > 0) {
                    StringBuilder sb = new StringBuilder("Errors found in the template");
                    for (TransformerException e : errors) {
                        sb.append("\n").append(e.getMessageAndLocation());
                    }
                   
                    throw new IOException(sb.toString());
                }
               
                return template;
            } catch(TransformerException e) {
                throw new IOException("Error found in the template: " + e.getMessageAndLocation());
            }
        }
    };

    public TransformRepository(GeoServerDataDirectory dataDir, Catalog catalog) {
        this.dataDir = dataDir;
        initXStream(catalog);
    }

    /**
     * Sets up xstream to get nice xml output
     *
     * @param catalog
     */
    private void initXStream(Catalog catalog) {
        xs = new XStream();
        xs.omitField(TransformInfo.class, "name");
        xs.alias("transform", TransformInfo.class);
        xs.registerLocalConverter(TransformInfo.class, "featureType", new ReferenceConverter(
                FeatureTypeInfo.class, catalog));
        xs.addDefaultImplementation(FeatureTypeInfoImpl.class, FeatureTypeInfo.class);
    }

    /**
     * The transform name is the same as the config file, minus the extension
     *
     * @param file
     * @return
     */
    protected String getTransformName(File file) {
        String name = file.getName();
        int idx = name.indexOf(".");
        if (idx > 0) {
            return name.substring(0, idx);
        } else {
            return name;
        }
    }

    /**
     * Returns all the transform (either global or feature type specific)
     *
     * @return
     */
    public List<TransformInfo> getAllTransforms() throws IOException {
        File root = dataDir.findOrCreateDir("wfs", "transform");
        List<TransformInfo> result = new ArrayList<TransformInfo>();
        for (File f : root.listFiles(CONFIG_NAME_FILTER)) {
            try {
                TransformInfo tx = infoCache.getItem(f);
                result.add(tx);
            } catch (Exception e) {
                LOGGER.log(Level.FINE,
                        "Failed to load configuration from file " + f.getAbsolutePath(), e);
            }
        }

        return result;
    }

    /**
     * Returns all the global transformations (not attached to a particular layer)
     *
     * @return
     */
    public List<TransformInfo> getGlobalTransforms() throws IOException {
        List<TransformInfo> allTransformations = getAllTransforms();
        List<TransformInfo> result = new ArrayList<TransformInfo>();
        for (TransformInfo ti : allTransformations) {
            if (ti.getFeatureType() == null) {
                result.add(ti);
            }
        }

        return result;
    }

    /**
     * Returns transformations associated to a specific feature type
     *
     * @param featureType
     * @return
     */
    public List<TransformInfo> getTypeTransforms(FeatureTypeInfo featureType) throws IOException {
        List<TransformInfo> allTransformations = getAllTransforms();
        List<TransformInfo> result = new ArrayList<TransformInfo>();
        for (TransformInfo ti : allTransformations) {
            if (ti.getFeatureType() != null
                    && ti.getFeatureType().getId().equals(featureType.getId())) {
                result.add(ti);
            }
        }

        return result;
    }

    /**
     * Returns a specific transformation by hand
     *
     * @param name
     * @return
     */
    public TransformInfo getTransformInfo(String name) throws IOException {
        File infoFile = getTransformInfoFile(name);
        return infoCache.getItem(infoFile);
    }
   
    /**
     * Deletes a transformation definition and its associated XSLT file (assuming the
     * latter is not shared with other transformations)
     *
     * @param info
     * @return
     * @throws IOException
     */
    public boolean removeTransformInfo(TransformInfo info) throws IOException {
         File infoFile = getTransformInfoFile(info.getName());
         boolean result = infoFile.delete();
        
         File xsltFile = getTransformFile(info);
         infoCache.removeItem(infoFile);
        
         boolean shared = false;
         if(xsltFile.exists()) {
             for(TransformInfo ti : getAllTransforms()) {
                 File curr = getTransformFile(ti);
                 if(curr.equals(xsltFile)) {
                     shared = true;
                     break;
                 }
             }
         }
         if(!shared) {
             result = result && xsltFile.delete();
             transformCache.removeItem(xsltFile);
         }
        
         return result;
    }

   
    /**
     * Returns the XSLT transformer for a specific {@link TransformInfo}
     *
     * @param name
     * @return
     */
    public Transformer getTransformer(TransformInfo info) throws IOException {
        File txFile = getTransformFile(info);

        Templates templates = transformCache.getItem(txFile);
        if(templates != null) {
            try {
                return templates.newTransformer();
            } catch (TransformerConfigurationException e) {
                throw new WFSException("Failed to load XSLT transformation " + info.getXslt(), e);
            }
        } else {
            throw new IOException("No XLST found at " + txFile.getAbsolutePath());
        }
    }
   
    /**
     * Returns the stylesheet of a transformation. It is the duty of the caller to close the input stream after reading it.
     * @return
     * @throws IOException
     */
    public InputStream getTransformSheet(TransformInfo info) throws IOException {
        File txFile = getTransformFile(info);
       
        return new FileInputStream(txFile);
    }

  
   
    /**
     * Writes the stylesheet of a transformation. This method will close the provided input stream.
     *
     * @param info
     * @param sheet
     * @throws IOException
     */
    public void putTransformSheet(TransformInfo info, InputStream sheet) throws IOException {
        File txFile = getTransformFile(info);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(txFile);
            IOUtils.copy(sheet, fos);
        } finally {
            IOUtils.closeQuietly(sheet);
            IOUtils.closeQuietly(fos);
        }
       
    }

    /**
     * Saves/updates the specified transformation
     *
     * @param transform
     * @throws IOException
     */
    public void putTransformInfo(TransformInfo transform) throws IOException {
        if (transform.getName() == null) {
            throw new IllegalArgumentException("Transformation does not have a name set");
        }
        File file = getTransformInfoFile(transform.getName());

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            xs.toXML(transform, fos);
        } finally {
            IOUtils.closeQuietly(fos);
        }

        infoCache.put(transform, file);
    }

    File getTransformInfoFile(String name) throws IOException {
        File root = dataDir.findOrCreateDir("wfs", "transform");
        File infoFile = new File(root, name + ".xml");
        return infoFile;
    }
   
    private File getTransformFile(TransformInfo info) throws IOException {
        String txName = info.getXslt();
        File root = dataDir.findOrCreateDir("wfs", "transform");
        File txFile = new File(root, txName);
        return txFile;
    }

   
}
TOP

Related Classes of org.geoserver.wfs.xslt.config.TransformRepository

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.