All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.vfny.geoserver.action.data.StylesEditorAction Maven / Gradle / Ivy

The newest version!
/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org.  All rights reserved.
 * This code is licensed under the GPL 2.0 license, availible at the root
 * application directory.
 */
package org.vfny.geoserver.action.data;

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
import org.apache.struts.util.MessageResources;
import org.geotools.styling.SLDParser;
import org.geotools.styling.Style;
import org.geotools.styling.StyleFactory;
import org.geotools.styling.StyleFactoryFinder;
import org.geotools.styling.StyledLayerDescriptor;
import org.vfny.geoserver.action.ConfigAction;
import org.vfny.geoserver.action.HTMLEncoder;
import org.vfny.geoserver.config.DataConfig;
import org.vfny.geoserver.config.StyleConfig;
import org.vfny.geoserver.form.data.StylesEditorForm;
import org.vfny.geoserver.global.ConfigurationException;
import org.vfny.geoserver.global.GeoserverDataDirectory;
import org.vfny.geoserver.global.UserContainer;
import org.vfny.geoserver.util.SLDValidator;
import org.xml.sax.SAXParseException;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * This class takes care of processing new sld files.  It makes use of a nice
 * upload button, checks to make sure the file isn't already in the system,
 * does a bit of validation, and then adds it to data config.
 *
 * @author rgould
 * @author Chris Holmes, Fulbright
 *
 * @task REVISIT: Still need to do the nice text box to edit the sld file
 *       directly. This will probably involve some trickiness - the work flow
 *       I am thinking is that an upload would just put it into the big style
 *       text box.  On a submit the text box would then be validated and
 *       written out to the file location.
 * @task TODO: write to a temp file before validation.  Right now we delete the
 *       file in the style directory.
 */
public class StylesEditorAction extends ConfigAction {
    public ActionForward execute(ActionMapping mapping, ActionForm form, UserContainer user,
        HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException {
        DataConfig config = (DataConfig) getDataConfig();
        StylesEditorForm stylesForm = (StylesEditorForm) form;
        FormFile file = stylesForm.getSldFile();
        final String styleID = stylesForm.getStyleID();
        final String originalStyleID = stylesForm.getOriginalStyleId();
        StyleConfig style = user.getStyle();
        boolean doFullValidation = stylesForm.getFullyValidate();
        String action = stylesForm.getAction();
        String sldContents = stylesForm.getSldContents();

        // decide what has been pressed
        Locale locale = (Locale) request.getLocale();
        MessageResources messages = getResources(request);

        // final String SUBMIT = HTMLEncoder.decode(messages.getMessage(locale, "label.submit"));
        final String UPLOAD = HTMLEncoder.decode(messages.getMessage(locale, "label.upload"));

        if (UPLOAD.equals(action)) {
            stylesForm.setSldContents(readSldContents(file));

            return mapping.findForward("config.data.style.editor");
        } else {
            if (stylesForm.getFullyValidateChecked() == false) {
                doFullValidation = false;
            }

            if (doFullValidation) {
                List l = getSchemaExceptions(sldContents, request);

                if (l.size() != 0) {
                    handleValidationErrors(l, sldContents, stylesForm);

                    return mapping.findForward("schemaErrors");
                }
            }

            if (style == null) {
                // Must of bookmarked? Redirect so they can select            
                return mapping.findForward("config.data.style");
            }

            //            ServletContext sc = getServlet().getServletContext();

            //DJB: changed for geoserver_data_dir
            //File rootDir = new File(getServlet().getServletContext().getRealPath("/"));
            File rootDir = GeoserverDataDirectory.getGeoserverDataDirectory();

            File styleDir;

            try {
                styleDir = GeoserverDataDirectory.findConfigDir(rootDir, "styles");
            } catch (ConfigurationException cfe) {
                LOGGER.warning("no style dir found, creating new one");
                //if for some bizarre reason we don't fine the dir, make a new one.
                styleDir = new File(rootDir, "styles");
            }

            // send content of FormFile to /styles :
            // there nothing to keep the styles in memory for XMLConfigWriter.store()
            StyleConfig styleForID = config.getStyle(originalStyleID);
            File newSldFile = null;

            if (styleForID != null) {
                // for backward compatibility, use the old style file
                File oldFile = styleForID.getFilename();
                newSldFile = oldFile;
            } else {
                newSldFile = new File(styleDir, styleID + ".sld");

                if (newSldFile.exists()) {
                    doFileExistsError(newSldFile, request);

                    return mapping.findForward("config.data.style.editor");
                }
            }

            //here we do a check to see if the file we are trying to upload is
            //overwriting another style file. 
            LOGGER.fine("new sld file is: " + newSldFile + ", exists: " + newSldFile.exists());

            //When we have time we should put this in a temp file, to be safe, before
            //we do the validation, and only write to the real style directory when we
            //have things set.  If only java had a nice file copy utility.
            FileWriter fw = new FileWriter(newSldFile);
            fw.write(sldContents);
            fw.flush();
            fw.close();
            style.setFilename(newSldFile);

            style.setId(styleID);

            StyleFactory factory = StyleFactoryFinder.createStyleFactory();
            SLDParser styleReader = new SLDParser(factory, newSldFile.toURL());
            Style[] readStyles = null;
            Style newStyle;

            try {
                readStyles = styleReader.readXML();

                if (readStyles.length == 0) {
                    //I think our style parser does pretty much no error reporting.
                    //This is one of the many reasons we need a new SLD parser.
                    //We could add new exceptions to it, but it's really just 
                    //patching a sinking ship.  One option that we could do
                    //here is do a xerces validating parse, to make sure the
                    //sld matches the schema before we try to pass it to our
                    //crappy parser.
                    String message = "The xml was valid, but couldn't get a Style"
                        + " from it.  Make sure your style validates against " + " the SLD schema";
                    doStyleParseError(message, newSldFile, request);

                    return mapping.findForward("config.data.style.editor");
                }

                newStyle = readStyles[0];
                LOGGER.fine("sld is " + newStyle);
            } catch (Exception e) {
                e.printStackTrace();

                String message = (e.getCause() == null) ? e.getLocalizedMessage()
                                                        : e.getCause().getLocalizedMessage();
                doStyleParseError(message, newSldFile, request);

                return mapping.findForward("config.data.style.editor");
            }

            if (newStyle == null) {
                throw new RuntimeException("new style equals null"); //I don't 

                //think this will ever happen, our SLD parser won't return a null.
            }

            // Do configuration parameters here
            config.removeStyle(originalStyleID);
            config.addStyle(style.getId(), style);
            getApplicationState().notifyConfigChanged();

            return mapping.findForward("config.data.style");
        }
    }

    private String readSldContents(FormFile file) throws IOException {
        StringBuffer sb = new StringBuffer();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new InputStreamReader(file.getInputStream()));

            String line = null;

            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
        } finally {
            reader.close();
        }

        return sb.toString();
    }

    /**
     *   make the validation report for the bean
     *   its a listing of the original file (prefixed by line #)
     *   and any validation errors
     *
         * @param l
         * @param file
         * @param stylesForm
         */
    private void handleValidationErrors(List errors, String sldContents, StylesEditorForm stylesForm) {
        ArrayList lines = new ArrayList();
        BufferedReader reader = null;

        try {
            reader = new BufferedReader(new StringReader(sldContents));

            String line = reader.readLine();
            int linenumber = 1;
            int exceptionNum = 0;

            //check for lineNumber -1 errors  --> invalid XML
            if (errors.size() > 0) {
                SAXParseException sax = (SAXParseException) errors.get(0);

                if (sax.getLineNumber() < 0) {
                    lines.add("   INVALID XML: " + sax.getLocalizedMessage());
                    lines.add(" ");
                    exceptionNum = 1; // skip ahead (you only ever get one error in this case)
                }
            }

            while (line != null) {
                line.replace('\n', ' ');
                line.replace('\r', ' ');

                String header = linenumber + ": ";
                lines.add(header + line); // record the current line

                boolean keep_going = true;

                while (keep_going) {
                    if ((exceptionNum < errors.size())) {
                        SAXParseException sax = (SAXParseException) errors.get(exceptionNum);

                        if (sax.getLineNumber() <= linenumber) {
                            String head = "---------------------".substring(0, header.length() - 1);
                            String body = "------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------";
                            int colNum = sax.getColumnNumber(); //protect against col 0 problems

                            if (colNum < 1) {
                                colNum = 1;
                            }

                            lines.add(head + body.substring(0, sax.getColumnNumber() - 1) + "^");
                            lines.add("       " + sax.getLocalizedMessage());
                            exceptionNum++;
                        } else {
                            keep_going = false; //report later (sax.getLineNumber() > linenumber)
                        }
                    } else {
                        keep_going = false; // no more errors to report
                    }
                }

                line = reader.readLine(); //will be null at eof
                linenumber++;
            }

            for (int t = exceptionNum; t < errors.size(); t++) {
                SAXParseException sax = (SAXParseException) errors.get(t);
                lines.add("       " + sax.getLocalizedMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        stylesForm.setValidationReport((String[]) lines.toArray(new String[1]));
    }

    /**
    *   Check the .sld file and check to see if it passes the validation test!
    *
     * @param file
     * @return
     */
    private List getSchemaExceptions(String sldContents, HttpServletRequest request) {
        SLDValidator validator = new SLDValidator();

        ServletContext sc = request.getSession().getServletContext();

        try {
            List l = validator.validateSLD(new ByteArrayInputStream(sldContents.getBytes("UTF-8")),
                    sc);

            return l;
        } catch (Exception e) {
            ArrayList al = new ArrayList();
            al.add(new SAXParseException(e.getLocalizedMessage(), null));

            return al;
        }
    }

    /*
    * Called when there is trouble parsing the file.  Note that we
    * also delete the file here, so it doesn't stick on the system.
    * Would be a bit better to write to a temp file before putting
    * it in the style directory, but so it goes.
    */
    private void doStyleParseError(String message, File newSldFile, HttpServletRequest request) {
        LOGGER.fine("parse error message is: " + message);

        ActionErrors errors = new ActionErrors();
        errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.style.noParse", message));
        saveErrors(request, errors);
        newSldFile.delete();
    }

    /*
     * reports an error for an attempt to upload an sld file that is already
     * in the system.*/
    private void doFileExistsError(File file, HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        errors.add(ActionErrors.GLOBAL_ERROR,
            new ActionError("error.style.sldFileExists", file.getName()));
        saveErrors(request, errors);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy