ingo@1115: /*
ingo@1115:  * Copyright (c) 2010 by Intevation GmbH
ingo@1115:  *
ingo@1115:  * This program is free software under the LGPL (>=v2.1)
ingo@1115:  * Read the file LGPL.txt coming with the software for details
ingo@1115:  * or visit http://www.gnu.org/licenses/ if it does not exist.
ingo@1115:  */
ingo@1115: 
ingo@647: package de.intevation.gnv.utils;
ingo@647: 
ingo@647: import java.io.File;
ingo@647: import java.io.FileNotFoundException;
ingo@647: import java.io.FileOutputStream;
ingo@647: import java.io.IOException;
ingo@647: import java.io.OutputStream;
tim@1070: import java.text.DecimalFormat;
ingo@772: import java.util.Date;
ingo@647: 
ingo@1057: import javax.xml.xpath.XPathConstants;
ingo@1057: 
ingo@647: import org.apache.log4j.Logger;
ingo@647: import org.w3c.dom.Document;
ingo@647: import org.w3c.dom.Element;
tim@859: import org.w3c.dom.Node;
ingo@647: 
tim@1070: import com.vividsolutions.jts.geom.Envelope;
tim@1070: 
sascha@1117: import de.intevation.artifacts.common.utils.XMLUtils;
tim@853: import de.intevation.artifacts.ArtifactNamespaceContext;
tim@853: import de.intevation.artifacts.CallContext;
tim@853: import de.intevation.gnv.artifacts.context.GNVArtifactContext;
tim@853: import de.intevation.gnv.wms.LayerInfo;
tim@853: 
ingo@647: /**
ingo@806:  * This class provides some methods to create files storing meta information
ingo@806:  * about wms layers and a map service which serves these layers.
sascha@807:  *
sascha@780:  * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
ingo@647:  */
ingo@647: public class MetaWriter {
ingo@647: 
ingo@647:     private static Logger logger = Logger.getLogger(MetaWriter.class);
ingo@647: 
ingo@647:     public static final String NODE_MAPSERVER = "mapserver";
ingo@647:     public static final String NODE_SERVER    = "server";
ingo@647:     public static final String NODE_MAP       = "map";
ingo@772:     public static final String NODE_TTL       = "ttl";
ingo@647: 
ingo@647:     public static final String META_FILE_NAME = "meta.xml";
tim@853: 
ingo@1057:     public static final String XPATH_META = "/art:meta";
tim@1070:     public static final String XPATH_MAPSERVER = "art:meta/art:"+NODE_MAPSERVER;
ingo@730: 
ingo@806:     /**
ingo@806:      * Constructor.
ingo@806:      */
ingo@647:     private MetaWriter() {
ingo@647:     }
sascha@778: 
ingo@806: 
ingo@806:     /**
ingo@1057:      * Just create a new document and insert the root node.
ingo@806:      *
ingo@1057:      * @return the meta document with necessary root node.
ingo@806:      */
ingo@1057:     public static Document initMeta() {
ingo@647:         Document meta = XMLUtils.newDocument();
ingo@647:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@647:             meta,
ingo@647:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@647:             ArtifactNamespaceContext.NAMESPACE_PREFIX);
ingo@647: 
ingo@647:         Element root = creator.create("meta");
ingo@647:         meta.appendChild(root);
ingo@647: 
ingo@1057:         return meta;
ingo@1057:     }
tim@655: 
ingo@1057:     public static boolean insertLayer(
ingo@1057:         CallContext context,
ingo@1057:         Document    document,
ingo@1057:         String      name,
ingo@1057:         String      title,
ingo@1057:         String      data,
ingo@1057:         String      model,
ingo@1057:         String      type,
ingo@1057:         String      status
ingo@1057:     ) {
ingo@1057:         if (document == null) {
ingo@1057:             document = initMeta();
tim@655:         }
ingo@1057: 
ingo@1057:         Node meta = (Node) XMLUtils.xpath(
ingo@1057:             document,
ingo@1057:             XPATH_META,
ingo@1057:             XPathConstants.NODE,
ingo@1057:             ArtifactNamespaceContext.INSTANCE);
ingo@1057: 
ingo@1057:         if (meta == null) {
ingo@1057:             logger.error("No meta node was found in the given document. "
ingo@1057:                 + "Cannot insert layer!");
ingo@1057:             return false;
ingo@1057:         }
ingo@1057: 
ingo@1057:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@1057:             document,
ingo@1057:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@1057:             ArtifactNamespaceContext.NAMESPACE_PREFIX);
ingo@1057: 
ingo@1057:         Element layerEl  = creator.create(LayerInfo.LAYER);
ingo@1057:         Element nameEl   = creator.create(LayerInfo.LAYER_NAME);
ingo@1057:         Element titleEl  = creator.create(LayerInfo.LAYER_TITLE);
ingo@1057:         Element dataEl   = creator.create(LayerInfo.LAYER_DATA);
ingo@1057:         Element modelEl  = creator.create(LayerInfo.LAYER_MODEL);
ingo@1057:         Element typeEl   = creator.create(LayerInfo.LAYER_TYPE);
ingo@1057:         Element statusEl = creator.create(LayerInfo.LAYER_STATUS);
ingo@1057: 
ingo@1057:         modelEl.setTextContent(model);
ingo@1057:         nameEl.setTextContent(name);
ingo@1057:         titleEl.setTextContent(title);
ingo@1057:         typeEl.setTextContent(type);
ingo@1057:         statusEl.setTextContent(status);
ingo@1057:         dataEl.setTextContent(data);
ingo@1057: 
ingo@1057:         layerEl.appendChild(modelEl);
ingo@1057:         layerEl.appendChild(nameEl);
ingo@1057:         layerEl.appendChild(titleEl);
ingo@1057:         layerEl.appendChild(dataEl);
ingo@1057:         layerEl.appendChild(typeEl);
ingo@1057:         layerEl.appendChild(statusEl);
ingo@1057: 
ingo@1057:         if (logger.isDebugEnabled()) {
ingo@1057:             logger.debug("--------------- WMS LAYER PARAMS ---------------");
ingo@1057:             logger.debug("Name  : " + name);
ingo@1057:             logger.debug("Title : " + title);
ingo@1057:             logger.debug("Data  : " + data);
ingo@1057:             logger.debug("Type  : " + type);
ingo@1057:             logger.debug("Model : " + model);
ingo@1057:             logger.debug("Status: " + status);
ingo@1057:         }
ingo@1057: 
ingo@1057:         meta.appendChild(layerEl);
ingo@1057: 
ingo@1057:         return true;
tim@655:     }
tim@655: 
tim@1070:     /**
tim@1070:      * Method to write the <i>meta</i> document down to a file.
tim@1070:      *
tim@1070:      * @param path The destination of the file.
tim@1070:      * @param meta The xml document storing the meta information.
tim@1070:      */
tim@1070:     public static boolean insertMbr(Envelope mbr, String srs, Document meta) {
tim@1070:         Node mapserverNode = (Node) XMLUtils.xpath(
tim@1070:                 meta,
tim@1070:                 XPATH_MAPSERVER,
tim@1070:                 XPathConstants.NODE,
tim@1070:                 ArtifactNamespaceContext.INSTANCE);
tim@1070:         if (mapserverNode != null){
tim@1070:             XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
tim@1070:                     meta,
tim@1070:                     ArtifactNamespaceContext.NAMESPACE_URI,
tim@1070:                     ArtifactNamespaceContext.NAMESPACE_PREFIX);
tim@1070:             Element bboxNode = creator.create("Box");
tim@1070:             bboxNode.setAttribute("srsName", srs);
tim@1070:             Element coordinateNode = creator.create("coordinates");
ingo@1057: 
tim@1070:             DecimalFormat formatter = new DecimalFormat("###.############");
tim@1070:             coordinateNode.setTextContent(formatter.format(mbr.getMinX()).replace(',', '.') +","+ 
tim@1070:                                           formatter.format(mbr.getMinY()).replace(',', '.')+" "+
tim@1070:                                           formatter.format(mbr.getMaxX()).replace(',', '.') +","+ 
tim@1070:                                           formatter.format(mbr.getMaxY()).replace(',', '.'));
tim@1070:             mapserverNode.appendChild(bboxNode);
tim@1070:             bboxNode.appendChild(coordinateNode);
tim@1070:         }
tim@1070:         return true;
tim@1070:     }
tim@655:     /**
ingo@806:      * Method to write the <i>meta</i> document down to a file.
ingo@806:      *
ingo@806:      * @param path The destination of the file.
ingo@806:      * @param meta The xml document storing the meta information.
tim@655:      */
tim@859:     public static boolean writeMetaFile(String path, Document meta) {
ingo@647:         try {
ingo@647:             File metaFile = new File(path, META_FILE_NAME);
ingo@647: 
ingo@730:             if (metaFile.exists()) {
ingo@730:                 logger.info("Delete old meta information file.");
ingo@730:                 metaFile.delete();
ingo@730:             }
ingo@730: 
ingo@647:             if (!metaFile.createNewFile() || !metaFile.canWrite()) {
ingo@647:                 logger.error("Error while writing meta file: "+metaFile.toString());
tim@655:                 return false;
ingo@647:             }
ingo@647: 
ingo@647:             OutputStream out = null;
ingo@647:             boolean success = false;
ingo@647:             try {
ingo@647:                 out = new FileOutputStream(metaFile);
ingo@647:                 success = XMLUtils.toStream(meta, out);
ingo@647:             }
ingo@647:             finally {
ingo@647:                 if (out != null) {
ingo@647:                     try { out.close(); }
ingo@647:                     catch (IOException ioe) {}
ingo@647:                 }
ingo@647:             }
ingo@647: 
ingo@647:             if (!success && metaFile.exists()) {
ingo@647:                 metaFile.delete();
ingo@647:             }
ingo@647: 
tim@655:             return success;
ingo@647:         }
ingo@647:         catch (FileNotFoundException fnfe) {
ingo@647:             logger.error(fnfe);
tim@655:             return false;
ingo@647:         }
ingo@647:         catch (IOException ioe) {
ingo@647:             logger.error(ioe, ioe);
tim@655:             return false;
ingo@647:         }
ingo@647:     }
ingo@647: 
ingo@647: 
ingo@806:     /**
ingo@806:      * Append meta information about the mapservice itself.
ingo@806:      *
ingo@806:      * @param callContext The CallContext object.
ingo@806:      * @param document The meta information document.
ingo@806:      * @param meta The element where the new information need to be appended to.
ingo@806:      */
ingo@1057:     public static void insertAbstractMeta(
ingo@647:         CallContext callContext,
ingo@1057:         Document    document
ingo@647:     ) {
ingo@1057:         if (document == null) {
ingo@1057:             document = initMeta();
ingo@1057:         }
ingo@1057: 
ingo@1057:         Node meta = (Node) XMLUtils.xpath(
ingo@1057:             document,
ingo@1057:             XPATH_META,
ingo@1057:             XPathConstants.NODE,
ingo@1057:             ArtifactNamespaceContext.INSTANCE);
ingo@1057: 
ingo@647:         XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator(
ingo@647:             document,
ingo@647:             ArtifactNamespaceContext.NAMESPACE_URI,
ingo@647:             ArtifactNamespaceContext.NAMESPACE_PREFIX);
ingo@647: 
ingo@647:         GNVArtifactContext context =
ingo@647:             (GNVArtifactContext) callContext.globalContext();
ingo@647: 
ingo@647:         String server = (String)
ingo@647:             context.get(GNVArtifactContext.MAPSERVER_SERVER_PATH_KEY);
ingo@647: 
ingo@647:         String map = (String)
ingo@647:             context.get(GNVArtifactContext.MAPSERVER_MAP_PATH_KEY);
ingo@647: 
ingo@1057:         Long time  = callContext.getTimeToLive();
ingo@1057:         time       = time != null ? time + new Date().getTime() : null;
ingo@1057:         String ttl = time != null ? time.toString() : null;
ingo@1057: 
ingo@772:         if (logger.isDebugEnabled()) {
ingo@772:             logger.debug("MAPSERVER PATH: " + server);
ingo@772:             logger.debug("MAP PATH: " + map);
ingo@1057:             logger.debug("TTL: " + ttl);
ingo@772:         }
ingo@647: 
ingo@647:         Element mapserver  = creator.create(NODE_MAPSERVER);
ingo@647:         Element serverPath = creator.create(NODE_SERVER);
ingo@647:         Element mapPath    = creator.create(NODE_MAP);
ingo@1057:         Element timetolive = creator.create(NODE_TTL);
ingo@647: 
ingo@647:         mapPath.setTextContent(map);
ingo@647:         serverPath.setTextContent(server);
ingo@1057:         timetolive.setTextContent(ttl);
ingo@647: 
ingo@647:         mapserver.appendChild(serverPath);
ingo@647:         mapserver.appendChild(mapPath);
ingo@1057:         mapserver.appendChild(timetolive);
ingo@647:         meta.appendChild(mapserver);
ingo@647:     }
ingo@647: }
ingo@647: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :